[SetupWizard] Implement GlifLayout

Bug: 25726515
Change-Id: Ib4ba64e648e52a9859fb6509a9ce41c692a20aa2
This commit is contained in:
Maurice Lam 2015-11-18 16:04:56 -08:00
parent 35cc29c9f3
commit fce4cf6161
9 changed files with 390 additions and 10 deletions

View file

@ -64,17 +64,18 @@
<!-- Specify the indeterminateTintMode to work around a bug in Lollipop -->
<item name="android:indeterminateTintMode" tools:ignore="NewApi">src_in</item>
<item name="android:navigationBarColor" tools:ignore="NewApi">@android:color/black</item>
<item name="android:statusBarColor" tools:ignore="NewApi">@android:color/black</item>
<item name="android:statusBarColor" tools:ignore="NewApi">?attr/colorPrimary</item>
<item name="android:textColorLink">@color/suw_link_color_light</item>
<item name="android:windowAnimationStyle">@style/Animation.SuwWindowAnimation</item>
<item name="android:windowDisablePreview">true</item>
<item name="android:windowSoftInputMode">adjustResize</item>
<item name="colorAccent">@color/suw_color_accent_light</item>
<item name="colorPrimary">@color/suw_color_accent_light</item>
<item name="listPreferredItemPaddingLeft">?attr/suwMarginSides</item>
<item name="listPreferredItemPaddingRight">?attr/suwMarginSides</item>
<item name="suwCardBackground">@drawable/suw_card_bg_light</item>
<item name="suwMarginSides">@dimen/suw_layout_margin_sides</item>
<item name="suwMarginSides">@dimen/suw_glif_margin_sides</item>
<item name="suwNavBarTheme">@style/SuwNavBarThemeLight</item>
<item name="textAppearanceListItemSmall">@style/TextAppearance.AppCompat.Body1</item>
</style>

View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/suw_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/suw_layout_icon"
style="@style/SuwGlifIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@null" />
<TextView
android:id="@+id/suw_layout_title"
style="@style/SuwGlifHeaderTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@+id/suw_layout_content"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>

View file

@ -17,6 +17,7 @@
<resources>
<!-- Theme attributes -->
<attr name="suwLayoutTheme" format="reference" />
<attr name="suwMarginSides" format="dimension|reference" />
@ -26,6 +27,9 @@
<attr name="suwNavBarTextColor" format="color" />
<attr name="suwNavBarTheme" format="reference" />
<!-- Custom view attributes -->
<attr name="suwHeaderText" format="string" localization="suggested" />
<declare-styleable name="SuwIllustration">
<attr name="suwAspectRatio" format="float" />
</declare-styleable>
@ -34,10 +38,16 @@
<attr name="suwHeader" format="reference" />
</declare-styleable>
<declare-styleable name="SuwGlifLayout">
<attr name="android:icon" />
<attr name="suwHeaderColor" format="reference|color" />
<attr name="suwHeaderText" />
</declare-styleable>
<declare-styleable name="SuwSetupWizardLayout">
<attr name="suwBackground" format="color|reference" />
<attr name="suwBackgroundTile" format="color|reference" />
<attr name="suwHeaderText" format="string" localization="suggested" />
<attr name="suwHeaderText" />
<attr name="suwDecorPaddingTop" format="dimension|reference" />
<attr name="suwIllustration" format="color|reference" />
<attr name="suwIllustrationAspectRatio" format="float|reference" />

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2015 The Android Open Source Project
@ -19,6 +19,8 @@
<!-- General -->
<dimen name="suw_layout_margin_sides">40dp</dimen>
<dimen name="suw_glif_margin_sides">24dp</dimen>
<dimen name="suw_glif_margin_top">24dp</dimen>
<!-- Content styles -->
<dimen name="suw_check_box_line_spacing_extra">4sp</dimen>
@ -69,6 +71,9 @@
<!-- This is the extra spacing required to make the leading exactly 32sp -->
<dimen name="suw_header_title_line_spacing_extra">3.67sp</dimen>
<dimen name="suw_glif_header_title_margin_top">24dp</dimen>
<dimen name="suw_glif_header_title_margin_bottom">8dp</dimen>
<!-- Illustration -->
<item name="suw_illustration_aspect_ratio" format="float" type="dimen">2.22</item>

View file

@ -96,19 +96,38 @@
<!-- Header layout (for phones) -->
<style name="SuwHeaderTitle">
<style name="SuwBaseHeaderTitle">
<!-- Before Honeycomb, layout_gravity is needed for FrameLayout to apply the margins -->
<item name="android:layout_gravity">top</item>
<item name="android:ellipsize">end</item>
<item name="android:maxLines">2</item>
<item name="android:textSize">@dimen/suw_header_title_size</item>
</style>
<style name="SuwHeaderTitle" parent="SuwBaseHeaderTitle">
<item name="android:layout_marginBottom">@dimen/suw_header_title_margin_bottom</item>
<item name="android:layout_marginLeft">?attr/suwMarginSides</item>
<item name="android:layout_marginRight">?attr/suwMarginSides</item>
<item name="android:ellipsize">end</item>
<item name="android:lineSpacingExtra">@dimen/suw_header_title_line_spacing_extra</item>
<item name="android:maxLines">2</item>
<item name="android:paddingBottom">@dimen/suw_header_title_padding_bottom</item>
<item name="android:paddingTop">@dimen/suw_header_title_padding_top</item>
<item name="android:textColor">@android:color/white</item>
<item name="android:textSize">@dimen/suw_header_title_size</item>
</style>
<!-- GLIF layout -->
<style name="SuwGlifHeaderTitle" parent="SuwBaseHeaderTitle">
<item name="android:layout_marginBottom">@dimen/suw_glif_header_title_margin_bottom</item>
<item name="android:layout_marginLeft">?attr/suwMarginSides</item>
<item name="android:layout_marginRight">?attr/suwMarginSides</item>
<item name="android:layout_marginTop">@dimen/suw_glif_header_title_margin_top</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
<style name="SuwGlifIcon">
<item name="android:layout_marginLeft">?attr/suwMarginSides</item>
<item name="android:layout_marginRight">?attr/suwMarginSides</item>
<item name="android:layout_marginTop">@dimen/suw_glif_margin_top</item>
</style>
<!-- Navigation bar styles -->

View file

@ -0,0 +1,175 @@
/*
* 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.Drawable;
import android.os.Build.VERSION_CODES;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ScrollView;
import android.widget.TextView;
/**
* 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";
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) {
final 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);
}
a.recycle();
}
@Override
protected View onInflateTemplate(LayoutInflater inflater, int template) {
if (template == 0) {
template = R.layout.suw_glif_template;
}
return super.onInflateTemplate(inflater, template);
}
@Override
protected ViewGroup findContainer(int containerId) {
if (containerId == 0) {
containerId = R.id.suw_layout_content;
}
return super.findContainer(containerId);
}
public ScrollView getScrollView() {
final View view = findViewById(R.id.suw_scroll_view);
return view instanceof ScrollView ? (ScrollView) view : null;
}
public void setHeaderText(int title) {
final TextView titleView = (TextView) findViewById(R.id.suw_layout_title);
if (titleView != null) {
titleView.setText(title);
}
}
public void setHeaderText(CharSequence title) {
final TextView titleView = (TextView) findViewById(R.id.suw_layout_title);
if (titleView != null) {
titleView.setText(title);
}
}
public CharSequence getHeaderText() {
final TextView titleView = (TextView) findViewById(R.id.suw_layout_title);
return titleView != null ? titleView.getText() : null;
}
public void setHeaderColor(ColorStateList color) {
final TextView titleView = (TextView) findViewById(R.id.suw_layout_title);
if (titleView != null) {
titleView.setTextColor(color);
}
}
public ColorStateList getHeaderColor() {
final TextView titleView = (TextView) findViewById(R.id.suw_layout_title);
return titleView != null ? titleView.getTextColors() : null;
}
public void setIcon(Drawable icon) {
final ImageView iconView = getIconView();
if (iconView != null) {
iconView.setImageDrawable(icon);
}
}
public Drawable getIcon() {
final ImageView iconView = getIconView();
return iconView != null ? iconView.getDrawable() : null;
}
private ImageView getIconView() {
return (ImageView) findViewById(R.id.suw_layout_icon);
}
}

View file

@ -66,13 +66,14 @@
<style name="SuwThemeGlif.Light" parent="android:Theme.Material.Light.NoActionBar">
<item name="android:colorAccent">@color/suw_color_accent_light</item>
<item name="android:colorPrimary">@color/suw_color_accent_light</item>
<item name="android:indeterminateTint">@color/suw_progress_bar_color_light</item>
<!-- Specify the indeterminateTintMode to work around a bug in Lollipop -->
<item name="android:indeterminateTintMode">src_in</item>
<item name="android:listPreferredItemPaddingEnd">?attr/suwMarginSides</item>
<item name="android:listPreferredItemPaddingStart">?attr/suwMarginSides</item>
<item name="android:navigationBarColor">@android:color/black</item>
<item name="android:statusBarColor">@android:color/black</item>
<item name="android:statusBarColor">?android:attr/colorPrimary</item>
<item name="android:textAppearanceListItemSmall">@android:style/TextAppearance.Material.Body1</item>
<item name="android:textColorLink">@color/suw_link_color_light</item>
<item name="android:windowAnimationStyle">@style/Animation.SuwWindowAnimation</item>
@ -80,7 +81,7 @@
<item name="android:windowSoftInputMode">adjustResize</item>
<item name="suwCardBackground">@drawable/suw_card_bg</item>
<item name="suwMarginSides">@dimen/suw_layout_margin_sides</item>
<item name="suwMarginSides">@dimen/suw_glif_margin_sides</item>
<item name="suwNavBarTheme">@style/SuwNavBarThemeLight</item>
</style>

View file

@ -0,0 +1,27 @@
<!--
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.
-->
<com.android.setupwizardlib.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/test_content"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.android.setupwizardlib.GlifLayout>

View file

@ -0,0 +1,92 @@
/*
* 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.test;
import android.content.Context;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ScrollView;
import android.widget.TextView;
import com.android.setupwizardlib.GlifLayout;
public class GlifLayoutTest extends InstrumentationTestCase {
private Context mContext;
@Override
protected void setUp() throws Exception {
super.setUp();
mContext = new ContextThemeWrapper(getInstrumentation().getContext(),
R.style.SuwThemeGlif_Light);
}
@SmallTest
public void testDefaultTemplate() {
GlifLayout layout = new GlifLayout(mContext);
assertDefaultTemplateInflated(layout);
}
@SmallTest
public void testSetHeaderText() {
GlifLayout layout = new GlifLayout(mContext);
TextView title = (TextView) layout.findViewById(R.id.suw_layout_title);
layout.setHeaderText("Abracadabra");
assertEquals("Header text should be \"Abracadabra\"", "Abracadabra", title.getText());
}
@SmallTest
public void testAddView() {
GlifLayout layout = new GlifLayout(mContext);
TextView tv = new TextView(mContext);
tv.setId(R.id.test_view_id);
layout.addView(tv);
assertDefaultTemplateInflated(layout);
View view = layout.findViewById(R.id.test_view_id);
assertSame("The view added should be the same text view", tv, view);
}
@SmallTest
public void testInflateFromXml() {
LayoutInflater inflater = LayoutInflater.from(mContext);
GlifLayout layout = (GlifLayout) inflater.inflate(R.layout.test_glif_layout, null);
assertDefaultTemplateInflated(layout);
View content = layout.findViewById(R.id.test_content);
assertTrue("@id/test_content should be a TextView", content instanceof TextView);
}
@SmallTest
public void testGetScrollView() {
GlifLayout layout = new GlifLayout(mContext);
assertNotNull("Get scroll view should not be null with default template",
layout.getScrollView());
}
private void assertDefaultTemplateInflated(GlifLayout layout) {
View title = layout.findViewById(R.id.suw_layout_title);
assertNotNull("@id/suw_layout_title should not be null", title);
View icon = layout.findViewById(R.id.suw_layout_icon);
assertNotNull("@id/suw_layout_icon should not be null", icon);
View scrollView = layout.findViewById(R.id.suw_scroll_view);
assertTrue("@id/suw_scroll_view should be a ScrollView", scrollView instanceof ScrollView);
}
}