Add center alignment for 2017 themes

Add "GLIF Pixel" theme that is a drop-in replacement for
SuwThemeGlif, which will center align the header and description
text.

To use GLIF Pixel theme, simply set the activity theme (using
android:theme or Activity#setTheme) to SuwThemeGlifPixel and use the
GLIF layouts normally.

Other theme attributes like status bar background will be done in a
separate CL.

Test: ./gradlew connectedAndroidTest test
Bug: 35446596
Change-Id: I3edee9cf80c1c84018ed08f47f9859e51a3936e6
This commit is contained in:
Maurice Lam 2017-02-28 11:09:45 -08:00
parent fca3ee628d
commit d3ffc713be
11 changed files with 149 additions and 32 deletions

View file

@ -88,6 +88,7 @@
<item name="listPreferredItemPaddingRight">?attr/suwMarginSides</item>
<item name="suwColorPrimary">?attr/colorPrimary</item>
<item name="suwDividerInset">@dimen/suw_items_glif_icon_divider_inset</item>
<item name="suwGlifHeaderGravity">start</item>
<item name="suwItemDescriptionStyle">@style/SuwItemContainer.Description.Glif</item>
<item name="suwListItemIconColor">@color/suw_list_item_icon_color_dark</item>
<item name="suwMarginSides">@dimen/suw_glif_margin_sides</item>
@ -116,6 +117,7 @@
<item name="listPreferredItemPaddingRight">?attr/suwMarginSides</item>
<item name="suwColorPrimary">?attr/colorPrimary</item>
<item name="suwDividerInset">@dimen/suw_items_glif_icon_divider_inset</item>
<item name="suwGlifHeaderGravity">start</item>
<item name="suwItemDescriptionStyle">@style/SuwItemContainer.Description.Glif</item>
<item name="suwListItemIconColor">@color/suw_list_item_icon_color_light</item>
<item name="suwMarginSides">@dimen/suw_glif_margin_sides</item>

View file

@ -16,6 +16,7 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/SuwGlifHeaderContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

View file

@ -48,12 +48,10 @@
<com.android.setupwizardlib.view.RichTextView
android:id="@+id/suw_items_title"
style="@style/SuwItemTitle"
style="@style/SuwItemTitle.Description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
android:textAlignment="viewStart"
android:textAppearance="@style/TextAppearance.SuwDescription"
tools:ignore="UnusedAttribute" />

View file

@ -21,6 +21,23 @@
<attr name="suwLayoutTheme" format="reference" />
<attr name="suwMarginSides" format="dimension|reference" />
<!-- Subset of values in "gravity" in frameworks/base/core/res/res/values/attrs.xml. Only
horizontal values are listed here as the header does not support vertical gravity. -->
<attr name="suwGlifHeaderGravity">
<!-- Push object to the left of its container, not changing its size. -->
<flag name="left" value="0x03" />
<!-- Push object to the right of its container, not changing its size. -->
<flag name="right" value="0x05" />
<!-- Place object in the horizontal center of its container, not changing its size. -->
<flag name="center_horizontal" value="0x01" />
<!-- Grow the horizontal size of the object if needed so it completely fills its container. -->
<flag name="fill_horizontal" value="0x07" />
<!-- Push object to the beginning of its container, not changing its size. -->
<flag name="start" value="0x00800003" />
<!-- Push object to the end of its container, not changing its size. -->
<flag name="end" value="0x00800005" />
</attr>
<attr name="suwCardBackground" format="color|reference" />
<attr name="suwDividerCondition">
<enum name="either" value="0" />

View file

@ -19,6 +19,14 @@
<!-- General styles -->
<style name="SuwThemeGlifPixel" parent="SuwThemeGlif">
<item name="suwGlifHeaderGravity">center_horizontal</item>
</style>
<style name="SuwThemeGlifPixel.Light" parent="SuwThemeGlif.Light">
<item name="suwGlifHeaderGravity">center_horizontal</item>
</style>
<style name="Animation.SuwWindowAnimation" parent="@android:style/Animation.Activity">
<item name="android:activityOpenEnterAnimation">@anim/suw_slide_next_in</item>
<item name="android:activityOpenExitAnimation">@anim/suw_slide_next_out</item>
@ -50,6 +58,8 @@
<!-- Ignore UnusedResources: Used by clients -->
<style name="SuwDescription.Glif" parent="SuwDescription" tools:ignore="UnusedResources">
<item name="android:layout_marginTop">@dimen/suw_description_glif_margin_top</item>
<item name="android:gravity">?attr/suwGlifHeaderGravity</item>
<item name="android:textAlignment" tools:targetApi="jelly_bean_mr1">gravity</item>
</style>
<style name="TextAppearance.SuwDescription.Light" parent="TextAppearance.SuwDescription">
@ -156,6 +166,11 @@
<item name="android:paddingTop">@dimen/suw_items_verbose_padding_vertical</item>
</style>
<style name="SuwItemTitle.Description" parent="SuwItemTitle">
<item name="android:gravity">?attr/suwGlifHeaderGravity</item>
<item name="android:textAlignment" tools:targetApi="jelly_bean_mr1">gravity</item>
</style>
<style name="SuwItemTitle.Verbose" parent="SuwItemTitle">
<item name="android:textAppearance">@style/TextAppearance.SuwGlifBody</item>
</style>
@ -168,12 +183,17 @@
<!-- GLIF layout -->
<style name="SuwGlifHeaderTitle" parent="SuwBaseHeaderTitle">
<item name="android:gravity">?attr/suwGlifHeaderGravity</item>
<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:textAlignment" tools:targetApi="jelly_bean_mr1">gravity</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
<style name="SuwGlifHeaderContainer">
<item name="android:gravity">?attr/suwGlifHeaderGravity</item>
</style>
<style name="SuwGlifIcon">
<item name="android:layout_marginLeft">?attr/suwMarginSides</item>

View file

@ -22,7 +22,7 @@ import android.support.annotation.StyleRes;
import android.view.ContextThemeWrapper;
/**
* Same as {@link ContextThemeWrapper}, but the base context's theme attributes take precendence
* Same as {@link ContextThemeWrapper}, but the base context's theme attributes take precedence
* over the wrapper context's. This is used to provide default values for theme attributes
* referenced in layouts, to remove the risk of crashing the client because of using the wrong
* theme.

View file

@ -52,16 +52,28 @@ public class WizardManagerHelper {
/**
* Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the dark variant of the
* theme used in setup wizard for NYC.
* theme used in setup wizard for Nougat MR1.
*/
public static final String THEME_GLIF = "glif";
/**
* Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the default theme used in
* setup wizard for NYC.
* setup wizard for Nougat MR1.
*/
public static final String THEME_GLIF_LIGHT = "glif_light";
/**
* Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the dark variant of the
* theme used in setup wizard for O DR.
*/
public static final String THEME_GLIF_PIXEL = "glif_pixel";
/**
* Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the default theme used in
* setup wizard for O DR.
*/
public static final String THEME_GLIF_PIXEL_LIGHT = "glif_pixel_light";
/**
* Get an intent that will invoke the next step of setup wizard.
*
@ -190,10 +202,10 @@ public class WizardManagerHelper {
*/
public static boolean isLightTheme(String theme, boolean def) {
if (THEME_HOLO_LIGHT.equals(theme) || THEME_MATERIAL_LIGHT.equals(theme)
|| THEME_GLIF_LIGHT.equals(theme)) {
|| THEME_GLIF_LIGHT.equals(theme) || THEME_GLIF_PIXEL_LIGHT.equals(theme)) {
return true;
} else if (THEME_HOLO.equals(theme) || THEME_MATERIAL.equals(theme)
|| THEME_GLIF.equals(theme)) {
|| THEME_GLIF.equals(theme) || THEME_GLIF_PIXEL.equals(theme)) {
return false;
} else {
return def;

View file

@ -91,6 +91,7 @@
<item name="suwColorPrimary">?android:attr/colorPrimary</item>
<item name="suwDividerInset">@dimen/suw_items_glif_icon_divider_inset</item>
<item name="suwGlifHeaderGravity">start</item>
<item name="suwItemDescriptionStyle">@style/SuwItemContainer.Description.Glif</item>
<item name="suwListItemIconColor">@color/suw_list_item_icon_color_dark</item>
<item name="suwMarginSides">@dimen/suw_glif_margin_sides</item>
@ -116,6 +117,7 @@
<item name="suwColorPrimary">?android:attr/colorPrimary</item>
<item name="suwDividerInset">@dimen/suw_items_glif_icon_divider_inset</item>
<item name="suwGlifHeaderGravity">start</item>
<item name="suwItemDescriptionStyle">@style/SuwItemContainer.Description.Glif</item>
<item name="suwListItemIconColor">@color/suw_list_item_icon_color_light</item>
<item name="suwMarginSides">@dimen/suw_glif_margin_sides</item>

View file

@ -23,12 +23,16 @@ import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
@ -76,6 +80,27 @@ public class GlifLayoutTest {
// This is a no-op because there is no progress bar stub
}
@Test
public void testGlifPixelTheme() {
mContext = new ContextThemeWrapper(InstrumentationRegistry.getContext(),
R.style.SuwThemeGlifPixel_Light);
final GlifLayout glifLayout = new GlifLayout(mContext);
final TextView titleView = (TextView) glifLayout.findManagedViewById(R.id.suw_layout_title);
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
assertEquals(View.TEXT_ALIGNMENT_GRAVITY, titleView.getTextAlignment());
}
assertEquals("Title text should be center aligned on GLIF Pixel theme",
Gravity.CENTER_HORIZONTAL, titleView.getGravity() & Gravity.CENTER_HORIZONTAL);
if (VERSION.SDK_INT >= VERSION_CODES.N) {
// LinearLayout.getGravity is only available on versions >= N
final View iconView = glifLayout.findManagedViewById(R.id.suw_layout_icon);
final LinearLayout parent = (LinearLayout) iconView.getParent();
assertEquals("Icon should be center aligned on GLIF Pixel theme",
Gravity.CENTER_HORIZONTAL, parent.getGravity() & Gravity.CENTER_HORIZONTAL);
}
}
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 file

@ -52,9 +52,7 @@ import org.robolectric.annotation.Config;
@RunWith(SuwLibRobolectricTestRunner.class)
@Config(
constants = BuildConfig.class,
sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK },
shadows = {
})
sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK })
public class ButtonItemTest {
private ViewGroup mParent;

View file

@ -14,25 +14,30 @@
* limitations under the License.
*/
package com.android.setupwizardlib.test;
package com.android.setupwizardlib.util;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.robolectric.RuntimeEnvironment.application;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.os.Build.VERSION_CODES;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import com.android.setupwizardlib.util.WizardManagerHelper;
import com.android.setupwizardlib.BuildConfig;
import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
@RunWith(AndroidJUnit4.class)
@SmallTest
@RunWith(SuwLibRobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = Config.NEWEST_SDK)
public class WizardManagerHelperTest {
@Test
@ -131,6 +136,26 @@ public class WizardManagerHelperTest {
WizardManagerHelper.isLightTheme(intent, true));
}
@Test
public void testGlifPixelIsDarkTheme() {
final Intent intent = new Intent();
intent.putExtra("theme", "glif_pixel");
assertFalse("Theme glif_pixel should be dark theme",
WizardManagerHelper.isLightTheme(intent, false));
assertFalse("Theme glif_pixel should be dark theme",
WizardManagerHelper.isLightTheme(intent, true));
}
@Test
public void testGlifPixelLightIsLightTheme() {
final Intent intent = new Intent();
intent.putExtra("theme", "glif_pixel_light");
assertTrue("Theme glif_pixel_light should be light theme",
WizardManagerHelper.isLightTheme(intent, false));
assertTrue("Theme glif_pixel_light should be light theme",
WizardManagerHelper.isLightTheme(intent, true));
}
@Test
public void testIsLightThemeDefault() {
final Intent intent = new Intent();
@ -166,25 +191,42 @@ public class WizardManagerHelperTest {
WizardManagerHelper.isLightTheme("abracadabra", false));
}
/**
* Test for {@link WizardManagerHelper#isUserSetupComplete(android.content.Context)}
*/
@TargetApi(VERSION_CODES.JELLY_BEAN_MR1)
@Test
public void testIsUserSetupComplete() {
// TODO (b/32975598): Move to Robolectric to test with different SDK versions, and inject
// values to Settings.Secure.
WizardManagerHelper.isUserSetupComplete(InstrumentationRegistry.getTargetContext());
// Stub: only test that no exception is thrown
Settings.Secure.putInt(application.getContentResolver(), Global.DEVICE_PROVISIONED, 1);
Settings.Secure.putInt(application.getContentResolver(), "user_setup_complete", 1);
assertTrue(WizardManagerHelper.isUserSetupComplete(application));
Settings.Secure.putInt(application.getContentResolver(), "user_setup_complete", 0);
assertFalse(WizardManagerHelper.isUserSetupComplete(application));
}
/**
* Test for {@link WizardManagerHelper#isDeviceProvisioned(android.content.Context)}
*/
@Test
@Config(sdk = VERSION_CODES.JELLY_BEAN)
public void testIsUserSetupCompleteCompat() {
Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 1);
assertTrue(WizardManagerHelper.isUserSetupComplete(application));
Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 0);
assertFalse(WizardManagerHelper.isUserSetupComplete(application));
}
@TargetApi(VERSION_CODES.JELLY_BEAN_MR1)
@Test
public void testIsDeviceProvisioned() {
// TODO: Move to Robolectric to test with different SDK versions, and inject values to
// Settings.Secure / Global.
WizardManagerHelper.isDeviceProvisioned(InstrumentationRegistry.getTargetContext());
// Stub: only test that no exception is thrown
Settings.Secure.putInt(application.getContentResolver(), Global.DEVICE_PROVISIONED, 1);
assertTrue(WizardManagerHelper.isDeviceProvisioned(application));
Settings.Secure.putInt(application.getContentResolver(), Global.DEVICE_PROVISIONED, 0);
assertFalse(WizardManagerHelper.isDeviceProvisioned(application));
}
@Test
@Config(sdk = VERSION_CODES.JELLY_BEAN)
public void testIsDeviceProvisionedCompat() {
Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 1);
assertTrue(WizardManagerHelper.isDeviceProvisioned(application));
Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 0);
assertFalse(WizardManagerHelper.isDeviceProvisioned(application));
}
}