summaryrefslogtreecommitdiff
path: root/library/main
diff options
context:
space:
mode:
Diffstat (limited to 'library/main')
-rw-r--r--library/main/res/values/attrs.xml17
-rw-r--r--library/main/src/com/android/setupwizardlib/GlifLayout.java131
-rw-r--r--library/main/src/com/android/setupwizardlib/SetupWizardLayout.java75
-rw-r--r--library/main/src/com/android/setupwizardlib/TemplateLayout.java47
-rw-r--r--library/main/src/com/android/setupwizardlib/template/ColoredHeaderMixin.java73
-rw-r--r--library/main/src/com/android/setupwizardlib/template/HeaderMixin.java95
-rw-r--r--library/main/src/com/android/setupwizardlib/template/IconMixin.java81
-rw-r--r--library/main/src/com/android/setupwizardlib/template/Mixin.java26
-rw-r--r--library/main/src/com/android/setupwizardlib/template/NavigationBarMixin.java83
-rw-r--r--library/main/src/com/android/setupwizardlib/template/ProgressBarMixin.java130
10 files changed, 585 insertions, 173 deletions
diff --git a/library/main/res/values/attrs.xml b/library/main/res/values/attrs.xml
index 1fedecc..984b6cd 100644
--- a/library/main/res/values/attrs.xml
+++ b/library/main/res/values/attrs.xml
@@ -35,7 +35,6 @@
<!-- Custom view attributes -->
<attr name="suwColorPrimary" format="color" />
<attr name="suwHeader" format="reference" />
- <attr name="suwHeaderText" format="string" localization="suggested" />
<attr name="suwDividerInset" format="dimension|reference" />
<attr name="suwItemDescriptionStyle" format="reference" />
@@ -52,10 +51,7 @@
</declare-styleable>
<declare-styleable name="SuwGlifLayout">
- <attr name="android:icon" />
<attr name="suwColorPrimary" />
- <attr name="suwHeaderColor" format="reference|color" />
- <attr name="suwHeaderText" />
</declare-styleable>
<declare-styleable name="SuwGlifListLayout">
@@ -75,7 +71,6 @@
<declare-styleable name="SuwSetupWizardLayout">
<attr name="suwBackground" format="color|reference" />
<attr name="suwBackgroundTile" format="color|reference" />
- <attr name="suwHeaderText" />
<attr name="suwDecorPaddingTop" format="dimension|reference" />
<attr name="suwIllustration" format="color|reference" />
<attr name="suwIllustrationAspectRatio" format="float|reference" />
@@ -122,4 +117,16 @@
<attr name="android:theme" />
</declare-styleable>
+ <declare-styleable name="SuwHeaderMixin">
+ <attr name="suwHeaderText" format="string" localization="suggested" />
+ </declare-styleable>
+
+ <declare-styleable name="SuwColoredHeaderMixin">
+ <attr name="suwHeaderColor" format="reference|color" />
+ </declare-styleable>
+
+ <declare-styleable name="SuwIconMixin">
+ <attr name="android:icon" />
+ </declare-styleable>
+
</resources>
diff --git a/library/main/src/com/android/setupwizardlib/GlifLayout.java b/library/main/src/com/android/setupwizardlib/GlifLayout.java
index 13d35fe..a6a852c 100644
--- a/library/main/src/com/android/setupwizardlib/GlifLayout.java
+++ b/library/main/src/com/android/setupwizardlib/GlifLayout.java
@@ -29,12 +29,14 @@ import android.view.InflateException;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewStub;
-import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.ScrollView;
import android.widget.TextView;
+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.view.StatusBarBackgroundLayout;
/**
@@ -88,29 +90,13 @@ public class GlifLayout extends TemplateLayout {
// 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));
+
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.SuwGlifLayout, defStyleAttr, 0);
- final Drawable icon = a.getDrawable(R.styleable.SuwGlifLayout_android_icon);
- if (icon != null) {
- setIcon(icon);
- }
-
- // Set the header color
- final ColorStateList headerColor =
- a.getColorStateList(R.styleable.SuwGlifLayout_suwHeaderColor);
- if (headerColor != null) {
- setHeaderColor(headerColor);
- }
-
-
- // Set the header text
- final CharSequence headerText =
- a.getText(R.styleable.SuwGlifLayout_suwHeaderText);
- if (headerText != null) {
- setHeaderText(headerText);
- }
-
ColorStateList primaryColor =
a.getColorStateList(R.styleable.SuwGlifLayout_suwColorPrimary);
@@ -149,72 +135,49 @@ public class GlifLayout extends TemplateLayout {
return super.findContainer(containerId);
}
- /**
- * Same as {@link android.view.View#findViewById(int)}, but may include views that are managed
- * by this view but not currently added to the view hierarchy. e.g. recycler view or list view
- * headers that are not currently shown.
- */
- protected View findManagedViewById(int id) {
- return findViewById(id);
- }
-
public ScrollView getScrollView() {
final View view = findManagedViewById(R.id.suw_scroll_view);
return view instanceof ScrollView ? (ScrollView) view : null;
}
public TextView getHeaderTextView() {
- return (TextView) findManagedViewById(R.id.suw_layout_title);
+ return getMixin(HeaderMixin.class).getTextView();
}
public void setHeaderText(int title) {
- setHeaderText(getContext().getResources().getText(title));
+ getMixin(HeaderMixin.class).setText(title);
}
public void setHeaderText(CharSequence title) {
- final TextView titleView = getHeaderTextView();
- if (titleView != null) {
- titleView.setText(title);
- }
+ getMixin(HeaderMixin.class).setText(title);
}
public CharSequence getHeaderText() {
- final TextView titleView = getHeaderTextView();
- return titleView != null ? titleView.getText() : null;
+ return getMixin(HeaderMixin.class).getText();
}
public void setHeaderColor(ColorStateList color) {
- final TextView titleView = getHeaderTextView();
- if (titleView != null) {
- titleView.setTextColor(color);
- }
+ final ColoredHeaderMixin mixin = (ColoredHeaderMixin) getMixin(HeaderMixin.class);
+ mixin.setColor(color);
}
public ColorStateList getHeaderColor() {
- final TextView titleView = getHeaderTextView();
- return titleView != null ? titleView.getTextColors() : null;
+ final ColoredHeaderMixin mixin = (ColoredHeaderMixin) getMixin(HeaderMixin.class);
+ return mixin.getColor();
}
public void setIcon(Drawable icon) {
- final ImageView iconView = getIconView();
- if (iconView != null) {
- iconView.setImageDrawable(icon);
- }
+ getMixin(IconMixin.class).setIcon(icon);
}
public Drawable getIcon() {
- final ImageView iconView = getIconView();
- return iconView != null ? iconView.getDrawable() : null;
- }
-
- protected ImageView getIconView() {
- return (ImageView) findManagedViewById(R.id.suw_layout_icon);
+ return getMixin(IconMixin.class).getIcon();
}
public void setPrimaryColor(ColorStateList color) {
mPrimaryColor = color;
setGlifPatternColor(color);
- setProgressBarColor(color);
+ getMixin(ProgressBarMixin.class).setColor(color);
}
public ColorStateList getPrimaryColor() {
@@ -239,64 +202,14 @@ public class GlifLayout extends TemplateLayout {
}
public boolean isProgressBarShown() {
- final View progressBar = findManagedViewById(R.id.suw_layout_progress);
- return progressBar != null && progressBar.getVisibility() == View.VISIBLE;
+ return getMixin(ProgressBarMixin.class).isShown();
}
public void setProgressBarShown(boolean shown) {
- if (shown) {
- View progressBar = getProgressBar();
- if (progressBar != null) {
- progressBar.setVisibility(View.VISIBLE);
- }
- } else {
- View progressBar = peekProgressBar();
- if (progressBar != null) {
- progressBar.setVisibility(View.GONE);
- }
- }
+ getMixin(ProgressBarMixin.class).setShown(shown);
}
- /**
- * Gets the progress bar in the layout. If the progress bar has not been used before, it will be
- * installed (i.e. inflated from its view stub).
- *
- * @return The progress bar of this layout. May be null only if the template used doesn't have a
- * progress bar built-in.
- */
- private ProgressBar getProgressBar() {
- final View progressBar = peekProgressBar();
- if (progressBar == null) {
- final ViewStub progressBarStub =
- (ViewStub) findManagedViewById(R.id.suw_layout_progress_stub);
- if (progressBarStub != null) {
- progressBarStub.inflate();
- }
- setProgressBarColor(mPrimaryColor);
- }
- return peekProgressBar();
- }
-
- /**
- * Gets the progress bar in the layout only if it has been installed.
- * {@link #setProgressBarShown(boolean)} should be called before this to ensure the progress bar
- * is set up correctly.
- *
- * @return The progress bar of this layout, or null if the progress bar is not installed. The
- * null case can happen either if {@link #setProgressBarShown(boolean)} with true was
- * not called before this, or if the template does not contain a progress bar.
- */
public ProgressBar peekProgressBar() {
- return (ProgressBar) findManagedViewById(R.id.suw_layout_progress);
- }
-
- private void setProgressBarColor(ColorStateList color) {
- if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- final ProgressBar bar = peekProgressBar();
- if (bar != null) {
- bar.setIndeterminateTintList(color);
- bar.setProgressBackgroundTintList(color);
- }
- }
+ return getMixin(ProgressBarMixin.class).peekProgressBar();
}
}
diff --git a/library/main/src/com/android/setupwizardlib/SetupWizardLayout.java b/library/main/src/com/android/setupwizardlib/SetupWizardLayout.java
index 79d9222..c30a12d 100644
--- a/library/main/src/com/android/setupwizardlib/SetupWizardLayout.java
+++ b/library/main/src/com/android/setupwizardlib/SetupWizardLayout.java
@@ -37,11 +37,12 @@ import android.view.InflateException;
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.HeaderMixin;
+import com.android.setupwizardlib.template.NavigationBarMixin;
+import com.android.setupwizardlib.template.ProgressBarMixin;
import com.android.setupwizardlib.util.RequireScrollHelper;
import com.android.setupwizardlib.view.BottomScrollView;
import com.android.setupwizardlib.view.Illustration;
@@ -51,8 +52,6 @@ public class SetupWizardLayout extends TemplateLayout {
private static final String TAG = "SetupWizardLayout";
- private ColorStateList mProgressBarColor;
-
public SetupWizardLayout(Context context) {
super(context, 0, 0);
init(null, R.attr.suwLayoutTheme);
@@ -81,6 +80,10 @@ public class SetupWizardLayout extends TemplateLayout {
// 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 HeaderMixin(this, attrs, defStyleAttr));
+ registerMixin(ProgressBarMixin.class, new ProgressBarMixin(this));
+ registerMixin(NavigationBarMixin.class, new NavigationBarMixin(this));
+
final TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.SuwSetupWizardLayout, defStyleAttr, 0);
@@ -132,13 +135,6 @@ public class SetupWizardLayout extends TemplateLayout {
}
setIllustrationAspectRatio(illustrationAspectRatio);
- // Set the header text
- final CharSequence headerText =
- a.getText(R.styleable.SuwSetupWizardLayout_suwHeaderText);
- if (headerText != null) {
- setHeaderText(headerText);
- }
-
a.recycle();
}
@@ -192,8 +188,7 @@ public class SetupWizardLayout extends TemplateLayout {
}
public NavigationBar getNavigationBar() {
- final View view = findManagedViewById(R.id.suw_layout_navigation_bar);
- return view instanceof NavigationBar ? (NavigationBar) view : null;
+ return getMixin(NavigationBarMixin.class).getNavigationBar();
}
public ScrollView getScrollView() {
@@ -213,26 +208,19 @@ public class SetupWizardLayout extends TemplateLayout {
}
public void setHeaderText(int title) {
- final TextView titleView = getHeaderTextView();
- if (titleView != null) {
- titleView.setText(title);
- }
+ getMixin(HeaderMixin.class).setText(title);
}
public void setHeaderText(CharSequence title) {
- final TextView titleView = getHeaderTextView();
- if (titleView != null) {
- titleView.setText(title);
- }
+ getMixin(HeaderMixin.class).setText(title);
}
public CharSequence getHeaderText() {
- final TextView titleView = getHeaderTextView();
- return titleView != null ? titleView.getText() : null;
+ return getMixin(HeaderMixin.class).getText();
}
public TextView getHeaderTextView() {
- return (TextView) findManagedViewById(R.id.suw_layout_title);
+ return getMixin(HeaderMixin.class).getTextView();
}
/**
@@ -375,18 +363,8 @@ public class SetupWizardLayout extends TemplateLayout {
}
}
- /**
- * Same as {@link android.view.View#findViewById(int)}, but may include views that are managed
- * by this view but not currently added to the view hierarchy. e.g. recycler view or list view
- * headers that are not currently shown.
- */
- protected View findManagedViewById(int id) {
- return findViewById(id);
- }
-
public boolean isProgressBarShown() {
- final View progressBar = findManagedViewById(R.id.suw_layout_progress);
- return progressBar != null && progressBar.getVisibility() == View.VISIBLE;
+ return getMixin(ProgressBarMixin.class).isShown();
}
/**
@@ -395,19 +373,7 @@ public class SetupWizardLayout extends TemplateLayout {
* view hierarchy until the first time this is set to {@code true}.
*/
public void setProgressBarShown(boolean shown) {
- final View progressBar = findManagedViewById(R.id.suw_layout_progress);
- if (progressBar != null) {
- progressBar.setVisibility(shown ? View.VISIBLE : View.GONE);
- } else if (shown) {
- final ViewStub progressBarStub =
- (ViewStub) findManagedViewById(R.id.suw_layout_progress_stub);
- if (progressBarStub != null) {
- progressBarStub.inflate();
- }
- if (mProgressBarColor != null) {
- setProgressBarColor(mProgressBarColor);
- }
- }
+ getMixin(ProgressBarMixin.class).setShown(shown);
}
/**
@@ -427,20 +393,11 @@ public class SetupWizardLayout extends TemplateLayout {
}
public void setProgressBarColor(ColorStateList color) {
- mProgressBarColor = color;
- if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- // Suppress lint error caused by
- // https://code.google.com/p/android/issues/detail?id=183136
- // noinspection AndroidLintWrongViewCast
- final ProgressBar bar = (ProgressBar) findViewById(R.id.suw_layout_progress);
- if (bar != null) {
- bar.setIndeterminateTintList(color);
- }
- }
+ getMixin(ProgressBarMixin.class).setColor(color);
}
public ColorStateList getProgressBarColor() {
- return mProgressBarColor;
+ return getMixin(ProgressBarMixin.class).getColor();
}
/* Misc */
diff --git a/library/main/src/com/android/setupwizardlib/TemplateLayout.java b/library/main/src/com/android/setupwizardlib/TemplateLayout.java
index 90666d2..3eae3af 100644
--- a/library/main/src/com/android/setupwizardlib/TemplateLayout.java
+++ b/library/main/src/com/android/setupwizardlib/TemplateLayout.java
@@ -28,6 +28,11 @@ import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
+import com.android.setupwizardlib.template.Mixin;
+
+import java.util.HashMap;
+import java.util.Map;
+
/**
* A generic template class that inflates a template, provided in the constructor or in
* {@code android:layout} through XML, and adds its children to a "container" in the template. When
@@ -42,6 +47,8 @@ public class TemplateLayout extends FrameLayout {
*/
private ViewGroup mContainer;
+ private Map<Class<? extends Mixin>, Mixin> mMixins = new HashMap<>();
+
public TemplateLayout(Context context, int template, int containerId) {
super(context);
init(template, containerId, null, R.attr.suwLayoutTheme);
@@ -74,6 +81,46 @@ public class TemplateLayout extends FrameLayout {
a.recycle();
}
+ /**
+ * Registers a mixin with a given class. This method should be called in the constructor.
+ *
+ * @param cls The class to register the mixin. In most cases, {@code cls} is the same as
+ * {@code mixin.getClass()}, but {@code cls} can also be a super class of that. In
+ * the latter case the the mixin must be retrieved using {@code cls} in
+ * {@link #getMixin(Class)}, not the subclass.
+ * @param mixin The mixin to be registered.
+ * @param <M> The class of the mixin to register. This is the same as {@code cls}
+ */
+ protected <M extends Mixin> void registerMixin(Class<M> cls, M mixin) {
+ mMixins.put(cls, mixin);
+ }
+
+ /**
+ * Same as {@link android.view.View#findViewById(int)}, but may include views that are managed
+ * by this view but not currently added to the view hierarchy. e.g. recycler view or list view
+ * headers that are not currently shown.
+ */
+ public View findManagedViewById(int id) {
+ return findViewById(id);
+ }
+
+ /**
+ * Get a {@link Mixin} from this template registered earlier in
+ * {@link #registerMixin(Class, Mixin)}.
+ *
+ * @param cls The class marker of Mixin being requested. The actual Mixin returned may be a
+ * subclass of this marker. Note that this must be the same class as registered in
+ * {@link #registerMixin(Class, Mixin)}, which is not necessarily the
+ * same as the concrete class of the instance returned by this method.
+ * @param <M> The type of the class marker.
+ * @return The mixin marked by {@code cls}, or null if the template does not have a matching
+ * mixin.
+ */
+ @SuppressWarnings("unchecked")
+ public <M extends Mixin> M getMixin(Class<M> cls) {
+ return (M) mMixins.get(cls);
+ }
+
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
mContainer.addView(child, index, params);
diff --git a/library/main/src/com/android/setupwizardlib/template/ColoredHeaderMixin.java b/library/main/src/com/android/setupwizardlib/template/ColoredHeaderMixin.java
new file mode 100644
index 0000000..ccc5aad
--- /dev/null
+++ b/library/main/src/com/android/setupwizardlib/template/ColoredHeaderMixin.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 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.template;
+
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+import com.android.setupwizardlib.R;
+import com.android.setupwizardlib.TemplateLayout;
+
+/**
+ * A {@link Mixin} displaying a header text that can be set to different colors. This Mixin is
+ * registered to the tempalte using HeaderMixin.class, and can be retrieved using:
+ * {@code (ColoredHeaderMixin) templateLayout.getMixin(HeaderMixin.class}.
+ */
+public class ColoredHeaderMixin extends HeaderMixin {
+
+ /**
+ * {@inheritDoc}
+ */
+ public ColoredHeaderMixin(TemplateLayout layout, AttributeSet attrs, int defStyleAttr) {
+ super(layout, attrs, defStyleAttr);
+
+ final TypedArray a = layout.getContext().obtainStyledAttributes(
+ attrs, R.styleable.SuwColoredHeaderMixin, defStyleAttr, 0);
+
+ // Set the header color
+ final ColorStateList headerColor =
+ a.getColorStateList(R.styleable.SuwColoredHeaderMixin_suwHeaderColor);
+ if (headerColor != null) {
+ setColor(headerColor);
+ }
+
+ a.recycle();
+ }
+
+ /**
+ * Sets the color of the header text. This can also be set via XML using
+ * {@code app:suwHeaderColor}.
+ *
+ * @param color The text color of the header.
+ */
+ public void setColor(ColorStateList color) {
+ final TextView titleView = getTextView();
+ if (titleView != null) {
+ titleView.setTextColor(color);
+ }
+ }
+
+ /**
+ * @return The current text color of the header.
+ */
+ public ColorStateList getColor() {
+ final TextView titleView = getTextView();
+ return titleView != null ? titleView.getTextColors() : null;
+ }
+}
diff --git a/library/main/src/com/android/setupwizardlib/template/HeaderMixin.java b/library/main/src/com/android/setupwizardlib/template/HeaderMixin.java
new file mode 100644
index 0000000..bd3f210
--- /dev/null
+++ b/library/main/src/com/android/setupwizardlib/template/HeaderMixin.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2017 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.template;
+
+import android.content.res.TypedArray;
+import android.support.annotation.AttrRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+import com.android.setupwizardlib.R;
+import com.android.setupwizardlib.TemplateLayout;
+
+/**
+ * A {@link Mixin} for setting and getting the header text.
+ */
+public class HeaderMixin implements Mixin {
+
+ private TemplateLayout mTemplateLayout;
+
+ /**
+ * @param layout The layout this Mixin belongs to.
+ * @param attrs XML attributes given to the layout.
+ * @param defStyleAttr The default style attribute as given to the constructor of the layout.
+ */
+ public HeaderMixin(@NonNull TemplateLayout layout, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr) {
+ mTemplateLayout = layout;
+
+ final TypedArray a = layout.getContext().obtainStyledAttributes(
+ attrs, R.styleable.SuwHeaderMixin, defStyleAttr, 0);
+
+ // Set the header text
+ final CharSequence headerText = a.getText(R.styleable.SuwHeaderMixin_suwHeaderText);
+ if (headerText != null) {
+ setText(headerText);
+ }
+
+ a.recycle();
+ }
+
+ /**
+ * @return The TextView displaying the header.
+ */
+ public TextView getTextView() {
+ return (TextView) mTemplateLayout.findManagedViewById(R.id.suw_layout_title);
+ }
+
+ /**
+ * Sets the header text. This can also be set via the XML attribute {@code app:suwHeaderText}.
+ *
+ * @param title The resource ID of the text to be set as header.
+ */
+ public void setText(int title) {
+ final TextView titleView = getTextView();
+ if (titleView != null) {
+ titleView.setText(title);
+ }
+ }
+
+ /**
+ * Sets the header text. This can also be set via the XML attribute {@code app:suwHeaderText}.
+ *
+ * @param title The text to be set as header.
+ */
+ public void setText(CharSequence title) {
+ final TextView titleView = getTextView();
+ if (titleView != null) {
+ titleView.setText(title);
+ }
+ }
+
+ /**
+ * @return The current header text.
+ */
+ public CharSequence getText() {
+ final TextView titleView = getTextView();
+ return titleView != null ? titleView.getText() : null;
+ }
+}
diff --git a/library/main/src/com/android/setupwizardlib/template/IconMixin.java b/library/main/src/com/android/setupwizardlib/template/IconMixin.java
new file mode 100644
index 0000000..46c23f0
--- /dev/null
+++ b/library/main/src/com/android/setupwizardlib/template/IconMixin.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 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.template;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import com.android.setupwizardlib.R;
+import com.android.setupwizardlib.TemplateLayout;
+
+/**
+ * A {@link Mixin} for setting an icon on the template layout.
+ */
+public class IconMixin implements Mixin {
+
+ private TemplateLayout mTemplateLayout;
+
+ /**
+ * @param layout The template layout that this Mixin is a part of.
+ * @param attrs XML attributes given to the layout.
+ * @param defStyleAttr The default style attribute as given to the constructor of the layout.
+ */
+ public IconMixin(TemplateLayout layout, AttributeSet attrs, int defStyleAttr) {
+ mTemplateLayout = layout;
+ final Context context = layout.getContext();
+
+ final TypedArray a =
+ context.obtainStyledAttributes(attrs, R.styleable.SuwIconMixin, defStyleAttr, 0);
+
+ final Drawable icon = a.getDrawable(R.styleable.SuwIconMixin_android_icon);
+ if (icon != null) {
+ setIcon(icon);
+ }
+
+ a.recycle();
+ }
+
+ /**
+ * Sets the icon on this layout. The icon can also be set in XML using {@code android:icon}.
+ *
+ * @param icon A drawable icon.
+ */
+ public void setIcon(Drawable icon) {
+ final ImageView iconView = getView();
+ if (iconView != null) {
+ iconView.setImageDrawable(icon);
+ }
+ }
+
+ /**
+ * @return The icon previously set in {@link #setIcon(Drawable)} or {@code android:icon}
+ */
+ public Drawable getIcon() {
+ final ImageView iconView = getView();
+ return iconView != null ? iconView.getDrawable() : null;
+ }
+
+ /**
+ * @return The ImageView responsible for displaying the icon.
+ */
+ protected ImageView getView() {
+ return (ImageView) mTemplateLayout.findManagedViewById(R.id.suw_layout_icon);
+ }
+}
diff --git a/library/main/src/com/android/setupwizardlib/template/Mixin.java b/library/main/src/com/android/setupwizardlib/template/Mixin.java
new file mode 100644
index 0000000..285ea31
--- /dev/null
+++ b/library/main/src/com/android/setupwizardlib/template/Mixin.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 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.template;
+
+/**
+ * Marker interface to indicate Mixin classes.
+ *
+ * @see TemplateLayout#registerMixin(Class, Mixin)
+ * @see TemplateLayout#getMixin(Class)
+ */
+public interface Mixin {
+}
diff --git a/library/main/src/com/android/setupwizardlib/template/NavigationBarMixin.java b/library/main/src/com/android/setupwizardlib/template/NavigationBarMixin.java
new file mode 100644
index 0000000..df35017
--- /dev/null
+++ b/library/main/src/com/android/setupwizardlib/template/NavigationBarMixin.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 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.template;
+
+import android.view.View;
+
+import com.android.setupwizardlib.R;
+import com.android.setupwizardlib.TemplateLayout;
+import com.android.setupwizardlib.view.NavigationBar;
+import com.android.setupwizardlib.view.NavigationBar.NavigationBarListener;
+
+/**
+ * A {@link Mixin} for interacting with a {@link NavigationBar}.
+ */
+public class NavigationBarMixin implements Mixin {
+
+ private TemplateLayout mTemplateLayout;
+
+ /**
+ * @param layout The layout this mixin belongs to.
+ */
+ public NavigationBarMixin(TemplateLayout layout) {
+ mTemplateLayout = layout;
+ }
+
+ /**
+ * @return The navigation bar instance in the layout, or null if the layout does not have a
+ * navigation bar.
+ */
+ public NavigationBar getNavigationBar() {
+ final View view = mTemplateLayout.findManagedViewById(R.id.suw_layout_navigation_bar);
+ return view instanceof NavigationBar ? (NavigationBar) view : null;
+ }
+
+ /**
+ * Sets the label of the next button.
+ *
+ * @param text Label of the next button.
+ */
+ public void setNextButtonText(int text) {
+ getNavigationBar().getNextButton().setText(text);
+ }
+
+ /**
+ * Sets the label of the next button.
+ *
+ * @param text Label of the next button.
+ */
+ public void setNextButtonText(CharSequence text) {
+ getNavigationBar().getNextButton().setText(text);
+ }
+
+ /**
+ * @return The current label of the next button.
+ */
+ public CharSequence getNextButtonText() {
+ return getNavigationBar().getNextButton().getText();
+ }
+
+ /**
+ * Sets the listener to handle back and next button clicks in the navigation bar.
+ *
+ * @see NavigationBar#setNavigationBarListener(NavigationBarListener)
+ * @see NavigationBarListener
+ */
+ public void setNavigationBarListener(NavigationBarListener listener) {
+ getNavigationBar().setNavigationBarListener(listener);
+ }
+}
diff --git a/library/main/src/com/android/setupwizardlib/template/ProgressBarMixin.java b/library/main/src/com/android/setupwizardlib/template/ProgressBarMixin.java
new file mode 100644
index 0000000..d5c038e
--- /dev/null
+++ b/library/main/src/com/android/setupwizardlib/template/ProgressBarMixin.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2017 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.template;
+
+import android.content.res.ColorStateList;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
+import android.support.annotation.Nullable;
+import android.view.View;
+import android.view.ViewStub;
+import android.widget.ProgressBar;
+
+import com.android.setupwizardlib.R;
+import com.android.setupwizardlib.TemplateLayout;
+
+/**
+ * A {@link Mixin} for showing a progress bar.
+ */
+public class ProgressBarMixin implements Mixin {
+
+ private TemplateLayout mTemplateLayout;
+
+ @Nullable
+ private ColorStateList mColor;
+
+ /**
+ * @param layout The layout this mixin belongs to.
+ */
+ public ProgressBarMixin(TemplateLayout layout) {
+ mTemplateLayout = layout;
+ }
+
+ /**
+ * @return True if the progress bar is currently shown.
+ */
+ public boolean isShown() {
+ final View progressBar = mTemplateLayout.findManagedViewById(R.id.suw_layout_progress);
+ return progressBar != null && progressBar.getVisibility() == View.VISIBLE;
+ }
+
+ /**
+ * Sets whether the progress bar is shown. If the progress bar has not been inflated from the
+ * stub, this method will inflate the progress bar.
+ *
+ * @param shown True to show the progress bar, false to hide it.
+ */
+ public void setShown(boolean shown) {
+ if (shown) {
+ View progressBar = getProgressBar();
+ if (progressBar != null) {
+ progressBar.setVisibility(View.VISIBLE);
+ }
+ } else {
+ View progressBar = peekProgressBar();
+ if (progressBar != null) {
+ progressBar.setVisibility(View.GONE);
+ }
+ }
+ }
+
+ /**
+ * Gets the progress bar in the layout. If the progress bar has not been used before, it will be
+ * installed (i.e. inflated from its view stub).
+ *
+ * @return The progress bar of this layout. May be null only if the template used doesn't have a
+ * progress bar built-in.
+ */
+ private ProgressBar getProgressBar() {
+ final View progressBar = peekProgressBar();
+ if (progressBar == null) {
+ final ViewStub progressBarStub =
+ (ViewStub) mTemplateLayout.findManagedViewById(R.id.suw_layout_progress_stub);
+ if (progressBarStub != null) {
+ progressBarStub.inflate();
+ }
+ setColor(mColor);
+ }
+ return peekProgressBar();
+ }
+
+ /**
+ * Gets the progress bar in the layout only if it has been installed.
+ * {@link #setShown(boolean)} should be called before this to ensure the progress bar
+ * is set up correctly.
+ *
+ * @return The progress bar of this layout, or null if the progress bar is not installed. The
+ * null case can happen either if {@link #setShown(boolean)} with true was
+ * not called before this, or if the template does not contain a progress bar.
+ */
+ public ProgressBar peekProgressBar() {
+ return (ProgressBar) mTemplateLayout.findManagedViewById(R.id.suw_layout_progress);
+ }
+
+ /**
+ * Sets the color of the indeterminate progress bar. This method is a no-op on SDK < 21.
+ */
+ public void setColor(@Nullable ColorStateList color) {
+ mColor = color;
+ if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ final ProgressBar bar = peekProgressBar();
+ if (bar != null) {
+ bar.setIndeterminateTintList(color);
+ bar.setProgressBackgroundTintList(color);
+ }
+ }
+ }
+
+ /**
+ * @return The color previously set in {@link #setColor(ColorStateList)}, or null if the color
+ * is not set. In case of null, the color of the progress bar will be inherited from the theme.
+ */
+ @Nullable
+ public ColorStateList getColor() {
+ return mColor;
+ }
+}