[automerger skipped] Migrate setup-wizard-lib to androidx. am: d533ee27e4 -s ours am: 216850a049 -s ours
am: 23e03d8d07 -s ours
Change-Id: If3386ef3ee0039ec4bec178f9e8ae4c3725f3973
diff --git a/library/gingerbread/res/drawable-xhdpi/suw_navbar_ic_down_arrow.png b/library/gingerbread/res/drawable-xhdpi/suw_navbar_ic_down_arrow.png
index 94016f4..a7084c5 100644
--- a/library/gingerbread/res/drawable-xhdpi/suw_navbar_ic_down_arrow.png
+++ b/library/gingerbread/res/drawable-xhdpi/suw_navbar_ic_down_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_down_arrow.png b/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_down_arrow.png
index 17811ae..ed3c3b0 100644
--- a/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_down_arrow.png
+++ b/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_down_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_left_arrow.png b/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_left_arrow.png
index 97fed92..be42712 100644
--- a/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_left_arrow.png
+++ b/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_left_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_right_arrow.png b/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_right_arrow.png
index f874955..d7bc4e3 100644
--- a/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_right_arrow.png
+++ b/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_right_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/drawable-xxxhdpi/suw_navbar_ic_down_arrow.png b/library/gingerbread/res/drawable-xxxhdpi/suw_navbar_ic_down_arrow.png
index cb6a422..dcc1f3c 100644
--- a/library/gingerbread/res/drawable-xxxhdpi/suw_navbar_ic_down_arrow.png
+++ b/library/gingerbread/res/drawable-xxxhdpi/suw_navbar_ic_down_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/layout/suw_items_switch.xml b/library/gingerbread/res/layout/suw_items_switch.xml
index 5296a62..5614044 100644
--- a/library/gingerbread/res/layout/suw_items_switch.xml
+++ b/library/gingerbread/res/layout/suw_items_switch.xml
@@ -17,17 +17,17 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- style="@style/SuwItemContainer.Verbose"
+ style="@style/SuwItemContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:clipToPadding="false"
+ android:baselineAligned="false"
android:orientation="horizontal">
<FrameLayout
android:id="@+id/suw_items_icon_container"
android:layout_width="@dimen/suw_items_icon_container_width"
android:layout_height="wrap_content"
- android:layout_gravity="top"
+ android:layout_gravity="center_vertical"
android:gravity="start">
<ImageView
@@ -41,13 +41,13 @@
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/suw_items_verbose_padding_bottom_extra"
+ android:layout_marginBottom="@dimen/suw_items_padding_bottom_extra"
android:layout_weight="1"
android:orientation="vertical">
<com.android.setupwizardlib.view.RichTextView
android:id="@+id/suw_items_title"
- style="@style/SuwItemTitle.Verbose"
+ style="@style/SuwItemTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
diff --git a/library/gingerbread/res/layout/suw_items_switch_verbose.xml b/library/gingerbread/res/layout/suw_items_switch_verbose.xml
new file mode 100644
index 0000000..8911acc
--- /dev/null
+++ b/library/gingerbread/res/layout/suw_items_switch_verbose.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2016 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ style="@style/SuwItemContainer.Verbose"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:baselineAligned="false"
+ android:clipToPadding="false"
+ android:orientation="horizontal"
+ tools:ignore="UnusedResources">
+ <!-- Ignore UnusedResources: can be used by clients -->
+
+ <FrameLayout
+ android:id="@+id/suw_items_icon_container"
+ android:layout_width="@dimen/suw_items_icon_container_width"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:gravity="start">
+
+ <ImageView
+ android:id="@+id/suw_items_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ tools:ignore="ContentDescription" />
+
+ </FrameLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/suw_items_verbose_padding_bottom_extra"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <com.android.setupwizardlib.view.RichTextView
+ android:id="@+id/suw_items_title"
+ style="@style/SuwItemTitle.Verbose"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="start"
+ android:labelFor="@+id/suw_items_switch"
+ android:textAlignment="viewStart"
+ tools:ignore="UnusedAttribute" />
+
+ <com.android.setupwizardlib.view.RichTextView
+ android:id="@+id/suw_items_summary"
+ style="@style/SuwItemSummary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="start"
+ android:textAlignment="viewStart"
+ android:visibility="gone"
+ tools:ignore="UnusedAttribute" />
+
+ </LinearLayout>
+
+ <androidx.appcompat.widget.SwitchCompat
+ android:id="@+id/suw_items_switch"
+ style="@style/SuwSwitchStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical" />
+
+</LinearLayout>
diff --git a/library/gingerbread/res/values-v21/styles.xml b/library/gingerbread/res/values-v21/styles.xml
new file mode 100644
index 0000000..3c0c254
--- /dev/null
+++ b/library/gingerbread/res/values-v21/styles.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 Google Inc.
+
+ 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.
+-->
+
+<resources xmlns:tools="http://schemas.android.com/tools">
+
+ <!-- Button styles -->
+
+ <style name="SuwGlifButton.Tertiary" parent="SuwGlifButton.BaseTertiary">
+ <item name="android:fontFamily">sans-serif-medium</item>
+ <item name="textAllCaps" tools:targetApi="ice_cream_sandwich">false</item>
+ </style>
+
+</resources>
diff --git a/library/gingerbread/res/values/styles.xml b/library/gingerbread/res/values/styles.xml
index 241f037..b008e1e 100644
--- a/library/gingerbread/res/values/styles.xml
+++ b/library/gingerbread/res/values/styles.xml
@@ -41,6 +41,7 @@
<item name="listPreferredItemPaddingRight">?attr/suwMarginSides</item>
<item name="suwButtonAllCaps">true</item>
<item name="suwButtonFontFamily">sans-serif</item>
+ <item name="suwButtonHighlightAlpha">0.24</item>
<item name="suwCardBackground">@drawable/suw_card_bg_dark</item>
<item name="suwDividerInsetEnd">0dp</item>
<item name="suwDividerInsetStart">@dimen/suw_items_icon_divider_inset</item>
@@ -75,6 +76,7 @@
<item name="listPreferredItemPaddingRight">?attr/suwMarginSides</item>
<item name="suwButtonAllCaps">true</item>
<item name="suwButtonFontFamily">sans-serif</item>
+ <item name="suwButtonHighlightAlpha">0.24</item>
<item name="suwCardBackground">@drawable/suw_card_bg_light</item>
<item name="suwDividerInsetEnd">0dp</item>
<item name="suwDividerInsetStart">@dimen/suw_items_icon_divider_inset</item>
@@ -109,7 +111,8 @@
<item name="listPreferredItemPaddingRight">?attr/suwMarginSides</item>
<item name="suwButtonAllCaps">true</item>
<item name="suwButtonCornerRadius">@dimen/suw_glif_button_corner_radius</item>
- <item name="suwButtonFontFamily">sans-serif</item>
+ <item name="suwButtonFontFamily">sans-serif-medium</item>
+ <item name="suwButtonHighlightAlpha">0.24</item>
<item name="suwColorPrimary">?attr/colorPrimary</item>
<item name="suwFillContentLayoutStyle">@style/SuwFillContentLayout</item>
<item name="suwDividerInsetEnd">0dp</item>
@@ -148,7 +151,8 @@
<item name="listPreferredItemPaddingRight">?attr/suwMarginSides</item>
<item name="suwButtonAllCaps">true</item>
<item name="suwButtonCornerRadius">@dimen/suw_glif_button_corner_radius</item>
- <item name="suwButtonFontFamily">sans-serif</item>
+ <item name="suwButtonFontFamily">sans-serif-medium</item>
+ <item name="suwButtonHighlightAlpha">0.12</item>
<item name="suwColorPrimary">?attr/colorPrimary</item>
<item name="suwFillContentLayoutStyle">@style/SuwFillContentLayout</item>
<item name="suwDividerInsetEnd">0dp</item>
@@ -262,6 +266,13 @@
<item name="colorControlHighlight">@color/suw_flat_button_highlight</item>
</style>
+ <!-- Ignore UnusedResources: used by clients -->
+ <style name="SuwGlifButton.Tertiary"
+ parent="SuwGlifButton.BaseTertiary"
+ tools:ignore="UnusedResources">
+ <item name="textAllCaps" tools:targetApi="ice_cream_sandwich">false</item>
+ </style>
+
<!-- Card layout (for tablets) -->
<style name="TextAppearance.SuwCardTitle" parent="@style/TextAppearance.AppCompat.Display1">
@@ -279,6 +290,10 @@
<style name="SuwFourColorIndeterminateProgressBar" parent="SuwBase.ProgressBarLarge">
<item name="android:layout_gravity">center</item>
<item name="android:indeterminate">true</item>
+ <item name="android:paddingEnd" tools:targetApi="17" >@dimen/suw_glif_progress_bar_padding</item>
+ <item name="android:paddingLeft">@dimen/suw_glif_progress_bar_padding</item>
+ <item name="android:paddingRight">@dimen/suw_glif_progress_bar_padding</item>
+ <item name="android:paddingStart" tools:targetApi="17" >@dimen/suw_glif_progress_bar_padding</item>
</style>
<!-- Navigation bar styles -->
diff --git a/library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java b/library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java
index 2a378e8..a0ea379 100644
--- a/library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java
+++ b/library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java
@@ -137,7 +137,7 @@
*
* @see ExploreByTouchHelper#dispatchHoverEvent(MotionEvent)
*/
- public final boolean dispatchHoverEvent(MotionEvent event) {
+ public boolean dispatchHoverEvent(MotionEvent event) {
return mDelegate instanceof ExploreByTouchHelper
&& ((ExploreByTouchHelper) mDelegate).dispatchHoverEvent(event);
}
diff --git a/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/util/LinkAccessibilityHelperTest.java b/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/util/LinkAccessibilityHelperTest.java
index 7b4ad4d..da07b40 100644
--- a/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/util/LinkAccessibilityHelperTest.java
+++ b/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/util/LinkAccessibilityHelperTest.java
@@ -31,13 +31,13 @@
import android.text.SpannableStringBuilder;
import android.util.DisplayMetrics;
import android.util.TypedValue;
-import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
import android.widget.TextView;
import androidx.core.text.BidiFormatter;
+import androidx.core.view.AccessibilityDelegateCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
import androidx.customview.widget.ExploreByTouchHelper;
@@ -242,7 +242,7 @@
@Test
public void testMethodDelegation() {
initTextView();
- ExploreByTouchHelper delegate = mock(TestPreOLinkAccessibilityHelper.class);
+ AccessibilityDelegateCompat delegate = mock(AccessibilityDelegateCompat.class);
LinkAccessibilityHelper helper = new LinkAccessibilityHelper(delegate);
AccessibilityEvent accessibilityEvent =
@@ -272,10 +272,6 @@
same(mTextView),
same(accessibilityEvent));
- MotionEvent motionEvent = MotionEvent.obtain(0, 0, 0, 0, 0, 0);
- helper.dispatchHoverEvent(motionEvent);
- verify(delegate).dispatchHoverEvent(eq(motionEvent));
-
helper.getAccessibilityNodeProvider(mTextView);
verify(delegate).getAccessibilityNodeProvider(same(mTextView));
diff --git a/library/gingerbread/test/robotest/src/com/android/setupwizardlib/items/SwitchItemTest.java b/library/gingerbread/test/robotest/src/com/android/setupwizardlib/items/SwitchItemTest.java
index 05d6e5b..4716c4d 100644
--- a/library/gingerbread/test/robotest/src/com/android/setupwizardlib/items/SwitchItemTest.java
+++ b/library/gingerbread/test/robotest/src/com/android/setupwizardlib/items/SwitchItemTest.java
@@ -31,6 +31,7 @@
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.appcompat.widget.SwitchCompat;
@@ -41,6 +42,7 @@
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
import org.robolectric.annotation.Config;
@RunWith(SuwLibRobolectricTestRunner.class)
@@ -50,11 +52,24 @@
private SwitchCompat mSwitch;
@Test
- public void testLayout() {
+ public void defaultLayout_baselineAligned_shouldBeFalse() {
Assume.assumeTrue(VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP);
- SwitchItem item = new SwitchItem();
LayoutInflater inflater = LayoutInflater.from(application);
- ViewGroup layout = (ViewGroup) inflater.inflate(item.getDefaultLayoutResource(), null);
+ SwitchItem item = new SwitchItem();
+ LinearLayout layout = (LinearLayout) inflater.inflate(item.getDefaultLayoutResource(),
+ null);
+ assertThat(layout.isBaselineAligned()).isFalse();
+ }
+
+ @Test
+ public void verboseLayout_clipPadding_shouldBeFalse() {
+ Assume.assumeTrue(VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP);
+ LayoutInflater inflater = LayoutInflater.from(application);
+ SwitchItem item = new SwitchItem(application,
+ Robolectric.buildAttributeSet()
+ .addAttribute(android.R.attr.layout, "@layout/suw_items_switch_verbose")
+ .build());
+ ViewGroup layout = (ViewGroup) inflater.inflate(item.getLayoutResource(), null);
assertThat(layout.getClipToPadding()).isFalse();
}
diff --git a/library/main/res/color-v23/suw_flat_button_highlight.xml b/library/main/res/color-v23/suw_flat_button_highlight.xml
index c5be14f..cdb1305 100644
--- a/library/main/res/color-v23/suw_flat_button_highlight.xml
+++ b/library/main/res/color-v23/suw_flat_button_highlight.xml
@@ -17,5 +17,5 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?android:attr/colorAccent"
- android:alpha="0.24" />
+ android:alpha="?attr/suwButtonHighlightAlpha" />
</selector>
diff --git a/library/main/res/values-as/strings.xml b/library/main/res/values-as/strings.xml
new file mode 100644
index 0000000..be6e06b
--- /dev/null
+++ b/library/main/res/values-as/strings.xml
@@ -0,0 +1,23 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="suw_next_button_label" msgid="7269625133873553978">"পৰৱৰ্তী"</string>
+ <string name="suw_back_button_label" msgid="1460929053642711025">"উভতি যাওক"</string>
+ <string name="suw_more_button_label" msgid="7769076059705546563">"অধিক"</string>
+</resources>
diff --git a/library/main/res/values-or/strings.xml b/library/main/res/values-or/strings.xml
new file mode 100644
index 0000000..c4d12ff
--- /dev/null
+++ b/library/main/res/values-or/strings.xml
@@ -0,0 +1,23 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="suw_next_button_label" msgid="7269625133873553978">"ପରବର୍ତ୍ତୀ"</string>
+ <string name="suw_back_button_label" msgid="1460929053642711025">"ପଛକୁ ଫେରନ୍ତୁ"</string>
+ <string name="suw_more_button_label" msgid="7769076059705546563">"ଅଧିକ"</string>
+</resources>
diff --git a/library/main/res/values-v21/styles.xml b/library/main/res/values-v21/styles.xml
index d2c27f6..fe71289 100644
--- a/library/main/res/values-v21/styles.xml
+++ b/library/main/res/values-v21/styles.xml
@@ -38,10 +38,6 @@
<!-- Button styles -->
- <style name="SuwGlifButton.Tertiary" parent="SuwGlifButton.BaseTertiary">
- <item name="android:fontFamily">sans-serif-medium</item>
- </style>
-
<style name="SuwBase.ProgressBarLarge" parent="@android:style/Widget.Material.ProgressBar.Large" />
<style name="SuwFourColorIndeterminateProgressBar" parent="SuwBase.ProgressBarLarge">
@@ -50,6 +46,8 @@
<item name="android:indeterminateDrawable">@drawable/suw_fourcolor_progress_bar</item>
<item name="android:indeterminateTint">@null</item>
<item name="android:indeterminateTintMode">@null</item>
+ <item name="android:paddingStart">@dimen/suw_glif_progress_bar_padding</item>
+ <item name="android:paddingEnd">@dimen/suw_glif_progress_bar_padding</item>
</style>
<!-- Items styles -->
diff --git a/library/main/res/values/attrs.xml b/library/main/res/values/attrs.xml
index b3fcfe9..86b27fa 100644
--- a/library/main/res/values/attrs.xml
+++ b/library/main/res/values/attrs.xml
@@ -21,6 +21,7 @@
<attr name="suwLayoutTheme" format="reference" />
<attr name="suwMarginSides" format="dimension|reference" />
<attr name="suwEditTextBackgroundColor" format="color" />
+ <attr name="suwButtonHighlightAlpha" format="float" />
<!-- 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. -->
diff --git a/library/main/res/values/dimens.xml b/library/main/res/values/dimens.xml
index 1a8b516..63980ab 100644
--- a/library/main/res/values/dimens.xml
+++ b/library/main/res/values/dimens.xml
@@ -31,7 +31,7 @@
<dimen name="suw_glif_footer_padding_vertical">8dp</dimen>
<dimen name="suw_glif_footer_min_height">72dp</dimen>
<dimen name="suw_glif_margin_sides">24dp</dimen>
- <dimen name="suw_glif_margin_top">48dp</dimen>
+ <dimen name="suw_glif_margin_top">56dp</dimen>
<dimen name="suw_glif_v3_button_corner_radius">4dp</dimen>
@@ -98,7 +98,7 @@
<!-- 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">15dp</dimen>
+ <dimen name="suw_glif_header_title_margin_top">16dp</dimen>
<dimen name="suw_glif_header_title_margin_bottom">2dp</dimen>
<dimen name="suw_glif_icon_max_height">32dp</dimen>
@@ -139,6 +139,7 @@
<!-- The margin to compensate for the padding built-in to the widget itself -->
<dimen name="suw_progress_bar_margin_vertical">-7dp</dimen>
<dimen name="suw_glif_progress_bar_margin_vertical">7dp</dimen>
+ <dimen name="suw_glif_progress_bar_padding">40dp</dimen>
<!-- Edit Text dimensions -->
<dimen name="suw_edit_text_min_height">56dp</dimen>
diff --git a/library/main/res/values/styles.xml b/library/main/res/values/styles.xml
index fa2a080..6c813b8 100644
--- a/library/main/res/values/styles.xml
+++ b/library/main/res/values/styles.xml
@@ -166,7 +166,7 @@
<!-- 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:maxLines">3</item>
<item name="android:textSize">@dimen/suw_header_title_size</item>
</style>
@@ -204,11 +204,6 @@
<item name="android:textAllCaps" tools:targetApi="ice_cream_sandwich">false</item>
</style>
- <!-- Ignore UnusedResources: used by clients -->
- <style name="SuwGlifButton.Tertiary"
- parent="SuwGlifButton.BaseTertiary"
- tools:ignore="UnusedResources" />
-
<!-- The start and end paddings are asymmetric because start buttons are borderless buttons
which aligns the text label. -->
<style name="SuwGlifButtonBar">
diff --git a/library/main/src/com/android/setupwizardlib/util/WizardManagerHelper.java b/library/main/src/com/android/setupwizardlib/util/WizardManagerHelper.java
index 0628192..9230b67 100644
--- a/library/main/src/com/android/setupwizardlib/util/WizardManagerHelper.java
+++ b/library/main/src/com/android/setupwizardlib/util/WizardManagerHelper.java
@@ -23,6 +23,7 @@
import android.os.Build.VERSION_CODES;
import android.provider.Settings;
+import androidx.annotation.Nullable;
import androidx.annotation.StyleRes;
import androidx.annotation.VisibleForTesting;
@@ -279,7 +280,25 @@
*/
public static @StyleRes int getThemeRes(Intent intent, @StyleRes int defaultTheme) {
final String theme = intent.getStringExtra(EXTRA_THEME);
- return getThemeRes(theme, defaultTheme);
+ return getThemeRes(theme, defaultTheme, null);
+ }
+
+ /**
+ * Gets the theme style resource defined by this library for the theme specified in the given
+ * intent. For example, for THEME_GLIF_LIGHT, the theme @style/SuwThemeGlif.Light is returned.
+ *
+ * @param intent The intent passed by setup wizard, or one with the theme propagated along using
+ * {@link #copyWizardManagerExtras(Intent, Intent)}.
+ * @return The style corresponding to the theme in the given intent, or {@code defaultTheme} if
+ * the given theme is not recognized. Return the {@code defaultTheme} if the specified
+ * theme is older than the oldest supported one.
+ *
+ * @see #getThemeRes(String, int)
+ */
+ public static @StyleRes int getThemeRes(Intent intent, @StyleRes int defaultTheme,
+ @Nullable String oldestSupportedTheme) {
+ final String theme = intent.getStringExtra(EXTRA_THEME);
+ return getThemeRes(theme, defaultTheme, oldestSupportedTheme);
}
/**
@@ -302,28 +321,91 @@
* given theme is not recognized.
*/
public static @StyleRes int getThemeRes(String theme, @StyleRes int defaultTheme) {
+ return getThemeRes(theme, defaultTheme, null);
+ }
+
+ /**
+ * Gets the theme style resource defined by this library for the given theme name. For example,
+ * for THEME_GLIF_LIGHT, the theme @style/SuwThemeGlif.Light is returned.
+ *
+ * <p>If you require extra theme attributes but want to ensure forward compatibility with new
+ * themes added here, consider overriding {@link android.app.Activity#onApplyThemeResource} in
+ * your activity and call {@link Theme#applyStyle(int, boolean)} using your theme overlay.
+ *
+ * <pre>{@code
+ * protected void onApplyThemeResource(Theme theme, int resid, boolean first) {
+ * super.onApplyThemeResource(theme, resid, first);
+ * theme.applyStyle(R.style.MyThemeOverlay, true);
+ * }
+ * }</pre>
+ *
+ * @param theme The string representation of the theme.
+ * @return The style corresponding to the given {@code theme}, or {@code defaultTheme} if the
+ * given theme is not recognized.
+ */
+ public static @StyleRes int getThemeRes(String theme, @StyleRes int defaultTheme,
+ @Nullable String oldestSupportedTheme) {
+ int returnedTheme = defaultTheme;
if (theme != null) {
switch (theme) {
case THEME_GLIF_V3_LIGHT:
- return R.style.SuwThemeGlifV3_Light;
+ returnedTheme = R.style.SuwThemeGlifV3_Light;
+ break;
case THEME_GLIF_V3:
- return R.style.SuwThemeGlifV3;
+ returnedTheme = R.style.SuwThemeGlifV3;
+ break;
case THEME_GLIF_V2_LIGHT:
- return R.style.SuwThemeGlifV2_Light;
+ returnedTheme = R.style.SuwThemeGlifV2_Light;
+ break;
case THEME_GLIF_V2:
- return R.style.SuwThemeGlifV2;
+ returnedTheme = R.style.SuwThemeGlifV2;
+ break;
case THEME_GLIF_LIGHT:
- return R.style.SuwThemeGlif_Light;
+ returnedTheme = R.style.SuwThemeGlif_Light;
+ break;
case THEME_GLIF:
- return R.style.SuwThemeGlif;
+ returnedTheme = R.style.SuwThemeGlif;
+ break;
case THEME_MATERIAL_LIGHT:
- return R.style.SuwThemeMaterial_Light;
+ returnedTheme = R.style.SuwThemeMaterial_Light;
+ break;
case THEME_MATERIAL:
- return R.style.SuwThemeMaterial;
+ returnedTheme = R.style.SuwThemeMaterial;
+ break;
+ default:
+ // fall through
+ }
+
+ // b/79540471 Return the default theme if the specified theme
+ // is older than the oldest supported one.
+ if (oldestSupportedTheme != null
+ && (getThemeVersion(theme) < getThemeVersion(oldestSupportedTheme))) {
+ returnedTheme = defaultTheme;
+ }
+ }
+
+ return returnedTheme;
+ }
+
+ private static int getThemeVersion(String theme) {
+ if (theme != null) {
+ switch (theme) {
+ case THEME_GLIF_V3_LIGHT:
+ case THEME_GLIF_V3:
+ return 4;
+ case THEME_GLIF_V2_LIGHT:
+ case THEME_GLIF_V2:
+ return 3;
+ case THEME_GLIF_LIGHT:
+ case THEME_GLIF:
+ return 2;
+ case THEME_MATERIAL_LIGHT:
+ case THEME_MATERIAL:
+ return 1;
default:
// fall through
}
}
- return defaultTheme;
+ return -1;
}
}
diff --git a/library/main/src/com/android/setupwizardlib/view/IllustrationVideoView.java b/library/main/src/com/android/setupwizardlib/view/IllustrationVideoView.java
index 6d31583..3c188e8 100644
--- a/library/main/src/com/android/setupwizardlib/view/IllustrationVideoView.java
+++ b/library/main/src/com/android/setupwizardlib/view/IllustrationVideoView.java
@@ -22,11 +22,17 @@
import android.graphics.SurfaceTexture;
import android.graphics.drawable.Animatable;
import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnErrorListener;
+import android.media.MediaPlayer.OnInfoListener;
+import android.media.MediaPlayer.OnPreparedListener;
+import android.media.MediaPlayer.OnSeekCompleteListener;
+import android.net.Uri;
import android.os.Build.VERSION_CODES;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
+import android.view.TextureView.SurfaceTextureListener;
import android.view.View;
import androidx.annotation.Nullable;
@@ -35,6 +41,8 @@
import com.android.setupwizardlib.R;
+import java.io.IOException;
+
/**
* A view for displaying videos in a continuous loop (without audio). This is typically used for
* animated illustrations.
@@ -49,10 +57,11 @@
*/
@TargetApi(VERSION_CODES.ICE_CREAM_SANDWICH)
public class IllustrationVideoView extends TextureView implements Animatable,
- TextureView.SurfaceTextureListener,
- MediaPlayer.OnPreparedListener,
- MediaPlayer.OnSeekCompleteListener,
- MediaPlayer.OnInfoListener {
+ SurfaceTextureListener,
+ OnPreparedListener,
+ OnSeekCompleteListener,
+ OnInfoListener,
+ OnErrorListener {
private static final String TAG = "IllustrationVideoView";
@@ -63,14 +72,19 @@
private @RawRes int mVideoResId = 0;
+ private String mVideoResPackageName;
+
@VisibleForTesting Surface mSurface;
+ private boolean mPrepared;
+
public IllustrationVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.SuwIllustrationVideoView);
- mVideoResId = a.getResourceId(R.styleable.SuwIllustrationVideoView_suwVideo, 0);
+ final int videoResId = a.getResourceId(R.styleable.SuwIllustrationVideoView_suwVideo, 0);
a.recycle();
+ setVideoResource(videoResId);
// By default the video scales without interpolation, resulting in jagged edges in the
// video. This works around it by making the view go through scaling, which will apply
@@ -99,16 +113,30 @@
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
}
+
+ /**
+ * Set the video and video package name to be played by this view.
+ *
+ * @param videoResId Resource ID of the video, typically an MP4 under res/raw.
+ * @param videoResPackageName The package name of videoResId.
+ */
+ public void setVideoResource(@RawRes int videoResId, String videoResPackageName) {
+ if (videoResId != mVideoResId
+ || (videoResPackageName != null && !videoResPackageName.equals(
+ mVideoResPackageName))) {
+ mVideoResId = videoResId;
+ mVideoResPackageName = videoResPackageName;
+ createMediaPlayer();
+ }
+ }
+
/**
* Set the video to be played by this view.
*
* @param resId Resource ID of the video, typically an MP4 under res/raw.
*/
public void setVideoResource(@RawRes int resId) {
- if (resId != mVideoResId) {
- mVideoResId = resId;
- createMediaPlayer();
- }
+ setVideoResource(resId, getContext().getPackageName());
}
@Override
@@ -125,7 +153,7 @@
* Creates a media player for the current URI. The media player will be started immediately if
* the view's window is visible. If there is an existing media player, it will be released.
*/
- private void createMediaPlayer() {
+ protected void createMediaPlayer() {
if (mMediaPlayer != null) {
mMediaPlayer.release();
}
@@ -133,25 +161,47 @@
return;
}
- mMediaPlayer = MediaPlayer.create(getContext(), mVideoResId);
+ mMediaPlayer = new MediaPlayer();
- if (mMediaPlayer != null) {
- mMediaPlayer.setSurface(mSurface);
- mMediaPlayer.setOnPreparedListener(this);
- mMediaPlayer.setOnSeekCompleteListener(this);
- mMediaPlayer.setOnInfoListener(this);
+ mMediaPlayer.setSurface(mSurface);
+ mMediaPlayer.setOnPreparedListener(this);
+ mMediaPlayer.setOnSeekCompleteListener(this);
+ mMediaPlayer.setOnInfoListener(this);
+ mMediaPlayer.setOnErrorListener(this);
- float aspectRatio =
- (float) mMediaPlayer.getVideoHeight() / mMediaPlayer.getVideoWidth();
- if (mAspectRatio != aspectRatio) {
- mAspectRatio = aspectRatio;
- requestLayout();
- }
- } else {
- Log.wtf(TAG, "Unable to initialize media player for video view");
+ setVideoResourceInternal(mVideoResId, mVideoResPackageName);
+ }
+
+ private void setVideoResourceInternal(@RawRes int videoRes, String videoResPackageName) {
+ Uri uri = Uri.parse("android.resource://" + videoResPackageName + "/" + videoRes);
+ try {
+ mMediaPlayer.setDataSource(getContext(), uri);
+ mMediaPlayer.prepareAsync();
+ } catch (IOException e) {
+ Log.wtf(TAG, "Unable to set data source", e);
}
- if (getWindowVisibility() == View.VISIBLE) {
- start();
+ }
+
+ protected void createSurface() {
+ if (mSurface != null) {
+ mSurface.release();
+ mSurface = null;
+ }
+ // Reattach only if it has been previously released
+ SurfaceTexture surfaceTexture = getSurfaceTexture();
+ if (surfaceTexture != null) {
+ setVisibility(View.INVISIBLE);
+ mSurface = new Surface(surfaceTexture);
+ }
+ }
+
+ @Override
+ protected void onWindowVisibilityChanged(int visibility) {
+ super.onWindowVisibilityChanged(visibility);
+ if (visibility == View.VISIBLE) {
+ reattach();
+ } else {
+ release();
}
}
@@ -169,9 +219,9 @@
*/
public void release() {
if (mMediaPlayer != null) {
- mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
+ mPrepared = false;
}
if (mSurface != null) {
mSurface.release();
@@ -179,14 +229,34 @@
}
}
+ private void reattach() {
+ if (mSurface == null) {
+ initVideo();
+ }
+ }
+
+ private void initVideo() {
+ if (getWindowVisibility() != View.VISIBLE) {
+ return;
+ }
+ createSurface();
+ if (mSurface != null) {
+ createMediaPlayer();
+ } else {
+ Log.w(TAG, "Surface creation failed");
+ }
+ }
+
+ protected void onRenderingStart() {
+ }
+
/* SurfaceTextureListener methods */
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
// Keep the view hidden until video starts
setVisibility(View.INVISIBLE);
- mSurface = new Surface(surfaceTexture);
- createMediaPlayer();
+ initVideo();
}
@Override
@@ -207,14 +277,14 @@
@Override
public void start() {
- if (mMediaPlayer != null && !mMediaPlayer.isPlaying()) {
+ if (mPrepared && mMediaPlayer != null && !mMediaPlayer.isPlaying()) {
mMediaPlayer.start();
}
}
@Override
public void stop() {
- if (mMediaPlayer != null) {
+ if (mPrepared && mMediaPlayer != null) {
mMediaPlayer.pause();
}
}
@@ -231,21 +301,52 @@
if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
// Video available, show view now
setVisibility(View.VISIBLE);
+ onRenderingStart();
}
return false;
}
@Override
public void onPrepared(MediaPlayer mp) {
+ mPrepared = true;
mp.setLooping(shouldLoop());
+
+ float aspectRatio = 0.0f;
+ if (mp.getVideoWidth() > 0 && mp.getVideoHeight() > 0) {
+ aspectRatio = (float) mp.getVideoHeight() / mp.getVideoWidth();
+ } else {
+ Log.w(TAG, "Unexpected video size=" + mp.getVideoWidth() + "x"
+ + mp.getVideoHeight());
+ }
+ if (Float.compare(mAspectRatio, aspectRatio) != 0) {
+ mAspectRatio = aspectRatio;
+ requestLayout();
+ }
+ if (getWindowVisibility() == View.VISIBLE) {
+ start();
+ }
}
@Override
public void onSeekComplete(MediaPlayer mp) {
- mp.start();
+ if (isPrepared()) {
+ mp.start();
+ } else {
+ Log.wtf(TAG, "Seek complete but media player not prepared");
+ }
}
public int getCurrentPosition() {
return mMediaPlayer == null ? 0 : mMediaPlayer.getCurrentPosition();
}
+
+ protected boolean isPrepared() {
+ return mPrepared;
+ }
+
+ @Override
+ public boolean onError(MediaPlayer mediaPlayer, int what, int extra) {
+ Log.w(TAG, "MediaPlayer error. what=" + what + " extra=" + extra);
+ return false;
+ }
}
diff --git a/library/platform/res/values-v27/styles.xml b/library/platform/res/values-v27/styles.xml
index 6e36919..70101c9 100644
--- a/library/platform/res/values-v27/styles.xml
+++ b/library/platform/res/values-v27/styles.xml
@@ -44,6 +44,7 @@
<item name="suwButtonAllCaps">true</item>
<item name="suwButtonFontFamily">sans-serif</item>
+ <item name="suwButtonHighlightAlpha">0.24</item>
<item name="suwCardBackground">@drawable/suw_card_bg</item>
<item name="suwFillContentLayoutStyle">@style/SuwFillContentLayout</item>
<item name="suwDividerInsetEnd">0dp</item>
@@ -75,6 +76,7 @@
<item name="suwButtonAllCaps">true</item>
<item name="suwButtonFontFamily">sans-serif</item>
+ <item name="suwButtonHighlightAlpha">0.24</item>
<item name="suwCardBackground">@drawable/suw_card_bg</item>
<item name="suwFillContentLayoutStyle">@style/SuwFillContentLayout</item>
<item name="suwDividerInsetEnd">0dp</item>
@@ -109,7 +111,8 @@
<item name="suwButtonAllCaps">true</item>
<item name="suwButtonCornerRadius">@dimen/suw_glif_button_corner_radius</item>
- <item name="suwButtonFontFamily">sans-serif</item>
+ <item name="suwButtonFontFamily">sans-serif-medium</item>
+ <item name="suwButtonHighlightAlpha">0.24</item>
<item name="suwColorPrimary">?android:attr/colorPrimary</item>
<item name="suwFillContentLayoutStyle">@style/SuwFillContentLayout</item>
<item name="suwDividerInsetEnd">0dp</item>
@@ -145,7 +148,8 @@
<item name="suwButtonAllCaps">true</item>
<item name="suwButtonCornerRadius">@dimen/suw_glif_button_corner_radius</item>
- <item name="suwButtonFontFamily">sans-serif</item>
+ <item name="suwButtonFontFamily">sans-serif-medium</item>
+ <item name="suwButtonHighlightAlpha">0.12</item>
<item name="suwColorPrimary">?android:attr/colorPrimary</item>
<item name="suwFillContentLayoutStyle">@style/SuwFillContentLayout</item>
<item name="suwDividerInsetEnd">0dp</item>
@@ -218,4 +222,11 @@
<item name="android:colorControlHighlight">@color/suw_flat_button_highlight</item>
</style>
+ <!-- Ignore UnusedResources: used by clients -->
+ <style name="SuwGlifButton.Tertiary"
+ parent="SuwGlifButton.BaseTertiary"
+ tools:ignore="UnusedResources">
+ <item name="android:fontFamily">sans-serif-medium</item>
+ </style>
+
</resources>
diff --git a/library/rules.gradle b/library/rules.gradle
index 9baa390..4e815ce 100644
--- a/library/rules.gradle
+++ b/library/rules.gradle
@@ -26,7 +26,7 @@
// Provides backwards compatibility for Gingerbread or above, using support libraries.
gingerbreadCompat {
dimension 'compat'
- minSdkVersion 9
+ minSdkVersion 14
}
}
diff --git a/library/self.gradle b/library/self.gradle
index a4bff4e..78e5011 100644
--- a/library/self.gradle
+++ b/library/self.gradle
@@ -25,8 +25,8 @@
res.srcDirs = ['test/instrumentation/res']
dependencies {
- androidTestImplementation 'com.android.support.test:rules:1.0.0'
- androidTestImplementation 'com.android.support.test:runner:1.0.0'
+ androidTestImplementation 'com.android.support.test:rules:1.0.1'
+ androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.google.dexmaker:dexmaker:1.2'
androidTestImplementation 'com.google.dexmaker:dexmaker-mockito:1.2'
androidTestImplementation 'com.google.truth:truth:0.31'
diff --git a/library/test/robotest/src/com/android/setupwizardlib/shadow/ShadowMediaPlayer.java b/library/test/robotest/src/com/android/setupwizardlib/shadow/ShadowMediaPlayer.java
new file mode 100644
index 0000000..7bcefd0
--- /dev/null
+++ b/library/test/robotest/src/com/android/setupwizardlib/shadow/ShadowMediaPlayer.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 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.shadow;
+
+import android.content.Context;
+import android.media.MediaPlayer;
+import android.net.Uri;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+import java.io.IOException;
+import java.net.HttpCookie;
+import java.util.List;
+import java.util.Map;
+
+@Implements(MediaPlayer.class)
+public class ShadowMediaPlayer extends org.robolectric.shadows.ShadowMediaPlayer {
+
+ private int mVideoWidth;
+ private int mVideoHeight;
+
+ public ShadowMediaPlayer() {
+ super();
+ mVideoWidth = -1;
+ mVideoHeight = -1;
+ }
+
+ @Implementation
+ public void setDataSource(
+ @NonNull Context context,
+ @NonNull Uri uri,
+ @Nullable Map<String, String> headers,
+ @Nullable List<HttpCookie> cookies)
+ throws IOException {
+ setDataSource(context, uri, headers);
+ }
+
+ @Implementation
+ public void seekTo(long msec, int mode) {
+ seekTo((int) msec);
+ }
+
+ public void setVideoSize(int width, int height) {
+ if (width < 0) {
+ throw new IllegalArgumentException("Unexpected negative width=" + width);
+ }
+ if (height < 0) {
+ throw new IllegalArgumentException("Unexpected negative height=" + height);
+ }
+
+ mVideoWidth = width;
+ mVideoHeight = height;
+ }
+
+ @Override
+ public int getVideoWidth() {
+ return mVideoWidth;
+ }
+
+ @Override
+ public int getVideoHeight() {
+ return mVideoHeight;
+ }
+}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/util/GlifStyleTest.java b/library/test/robotest/src/com/android/setupwizardlib/util/GlifStyleTest.java
index d8e318d..195fc9b 100644
--- a/library/test/robotest/src/com/android/setupwizardlib/util/GlifStyleTest.java
+++ b/library/test/robotest/src/com/android/setupwizardlib/util/GlifStyleTest.java
@@ -28,6 +28,7 @@
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
+import android.util.AttributeSet;
import android.view.ContextThemeWrapper;
import android.widget.Button;
import android.widget.ProgressBar;
@@ -37,27 +38,21 @@
import com.android.setupwizardlib.R;
import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
+import org.robolectric.util.ReflectionHelpers.ClassParameter;
@RunWith(SuwLibRobolectricTestRunner.class)
@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK})
public class GlifStyleTest {
- private Context mContext;
-
- @Before
- public void setUp() {
- mContext = new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light);
- }
-
@Test
public void testSuwGlifButtonTertiary() {
- Button button = new Button(
- mContext,
+ Button button = createButton(
+ new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light),
Robolectric.buildAttributeSet()
.setStyleAttribute("@style/SuwGlifButton.Tertiary")
.build());
@@ -87,6 +82,22 @@
activity.findViewById(R.id.suw_large_progress_bar) instanceof ProgressBar);
}
+ private Button createButton(Context context, AttributeSet attrs) {
+ Class<? extends Button> buttonClass;
+ try {
+ // Use AppCompatButton in builds that have them (i.e. gingerbreadCompat)
+ // noinspection unchecked
+ buttonClass = (Class<? extends Button>)
+ Class.forName("androidx.appcompat.widget.AppCompatButton");
+ } catch (ClassNotFoundException e) {
+ buttonClass = Button.class;
+ }
+ return ReflectionHelpers.callConstructor(
+ buttonClass,
+ ClassParameter.from(Context.class, context),
+ ClassParameter.from(AttributeSet.class, attrs));
+ }
+
private static class GlifThemeActivity extends Activity {
@Override
diff --git a/library/test/robotest/src/com/android/setupwizardlib/util/WizardManagerHelperTest.java b/library/test/robotest/src/com/android/setupwizardlib/util/WizardManagerHelperTest.java
index 616ccdd..20549f2 100644
--- a/library/test/robotest/src/com/android/setupwizardlib/util/WizardManagerHelperTest.java
+++ b/library/test/robotest/src/com/android/setupwizardlib/util/WizardManagerHelperTest.java
@@ -162,6 +162,22 @@
}
@Test
+ public void getThemeRes_whenOldestSupportedThemeTakeEffect_shouldReturnDefault() {
+ Intent intent = new Intent();
+ intent.putExtra(WizardManagerHelper.EXTRA_THEME, "material");
+ assertEquals(0,
+ WizardManagerHelper.getThemeRes(intent, 0, WizardManagerHelper.THEME_GLIF_V2));
+ }
+
+ @Test
+ public void getThemeRes_whenOldestSupportedThemeNotTakeEffect_shouldReturnCurrent() {
+ Intent intent = new Intent();
+ intent.putExtra(WizardManagerHelper.EXTRA_THEME, "glif_v3");
+ assertEquals(R.style.SuwThemeGlifV3,
+ WizardManagerHelper.getThemeRes(intent, 0, WizardManagerHelper.THEME_GLIF_V2));
+ }
+
+ @Test
public void testIsLightThemeDefault() {
final Intent intent = new Intent();
intent.putExtra("theme", "abracadabra");
diff --git a/library/test/robotest/src/com/android/setupwizardlib/view/IllustrationVideoViewTest.java b/library/test/robotest/src/com/android/setupwizardlib/view/IllustrationVideoViewTest.java
index 1be822d..a6c1808 100644
--- a/library/test/robotest/src/com/android/setupwizardlib/view/IllustrationVideoViewTest.java
+++ b/library/test/robotest/src/com/android/setupwizardlib/view/IllustrationVideoViewTest.java
@@ -16,51 +16,52 @@
package com.android.setupwizardlib.view;
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
import static org.robolectric.RuntimeEnvironment.application;
import android.annotation.TargetApi;
-import android.content.Context;
+import android.app.Activity;
import android.graphics.SurfaceTexture;
-import android.media.MediaPlayer;
+import android.net.Uri;
import android.os.Build.VERSION_CODES;
import android.view.Surface;
+import android.view.View;
import androidx.annotation.RawRes;
import com.android.setupwizardlib.R;
import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
import com.android.setupwizardlib.shadow.ShadowLog;
-import com.android.setupwizardlib.shadow.ShadowLog.TerribleFailure;
-import com.android.setupwizardlib.view.IllustrationVideoViewTest.ShadowMockMediaPlayer;
+import com.android.setupwizardlib.shadow.ShadowMediaPlayer;
import com.android.setupwizardlib.view.IllustrationVideoViewTest.ShadowSurface;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
+import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
-import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.RealObject;
import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.ShadowMediaPlayer;
+import org.robolectric.shadows.ShadowMediaPlayer.InvalidStateBehavior;
+import org.robolectric.shadows.ShadowMediaPlayer.MediaInfo;
+import org.robolectric.shadows.ShadowMediaPlayer.State;
+import org.robolectric.shadows.util.DataSource;
import org.robolectric.util.ReflectionHelpers;
+import org.robolectric.util.ReflectionHelpers.ClassParameter;
@RunWith(SuwLibRobolectricTestRunner.class)
@Config(
sdk = Config.NEWEST_SDK,
shadows = {
ShadowLog.class,
- ShadowMockMediaPlayer.class,
+ ShadowMediaPlayer.class,
ShadowSurface.class
})
public class IllustrationVideoViewTest {
@@ -70,48 +71,58 @@
private IllustrationVideoView mView;
+ private ShadowMediaPlayer mShadowMediaPlayer;
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- }
-
- @After
- public void tearDown() {
- ShadowMockMediaPlayer.reset();
+ addMediaInfo(android.R.color.white);
}
@Test
- public void nullMediaPlayer_shouldThrowWtf() {
- ShadowMockMediaPlayer.sMediaPlayer = null;
- try {
- createDefaultView();
- fail("WTF should be thrown for null media player");
- } catch (TerribleFailure e) {
- // pass
- }
+ public void onVisibilityChanged_notVisible_shouldRelease() {
+
+ createDefaultView();
+ mView.onWindowVisibilityChanged(View.GONE);
+
+ assertThat(mShadowMediaPlayer.getState()).isEqualTo(State.END);
+ assertThat(mView.mSurface).isNull();
+ assertThat(mView.mMediaPlayer).isNull();
+ }
+
+ @Test
+ public void onVisibilityChanged_visible_shouldPlay() {
+ createDefaultView();
+
+ mView.onWindowVisibilityChanged(View.GONE);
+ assertThat(mView.mSurface).isNull();
+ assertThat(mView.mMediaPlayer).isNull();
+
+ mView.onWindowVisibilityChanged(View.VISIBLE);
+
+ assertThat(mView.mSurface).isNotNull();
+ assertThat(mView.mMediaPlayer).isNotNull();
}
@Test
public void testPausedWhenWindowFocusLost() {
createDefaultView();
+ Robolectric.flushForegroundThreadScheduler();
mView.start();
assertNotNull(mView.mMediaPlayer);
assertNotNull(mView.mSurface);
mView.onWindowFocusChanged(false);
- verify(ShadowMockMediaPlayer.getMock()).pause();
+ assertThat(mShadowMediaPlayer.getState()).isEqualTo(State.PAUSED);
}
@Test
public void testStartedWhenWindowFocusRegained() {
testPausedWhenWindowFocusLost();
- // Clear verifications for calls in the other test
- reset(ShadowMockMediaPlayer.getMock());
-
mView.onWindowFocusChanged(true);
- verify(ShadowMockMediaPlayer.getMock()).start();
+ assertThat(mShadowMediaPlayer.getState()).isEqualTo(State.STARTED);
}
@Test
@@ -123,55 +134,164 @@
assertNotNull(mView.mSurface);
mView.onSurfaceTextureDestroyed(mSurfaceTexture);
- verify(ShadowMockMediaPlayer.getMock()).release();
+ assertThat(mShadowMediaPlayer.getState()).isEqualTo(State.END);
}
@Test
public void testXmlSetVideoResId() {
createDefaultView();
- assertEquals(android.R.color.white, ShadowMockMediaPlayer.sResId);
+ assertThat(mShadowMediaPlayer.getSourceUri().toString())
+ .isEqualTo("android.resource://com.android.setupwizardlib/"
+ + android.R.color.white);
}
@Test
public void testSetVideoResId() {
+ addMediaInfo(android.R.color.black);
+
createDefaultView();
@RawRes int black = android.R.color.black;
mView.setVideoResource(black);
- assertEquals(android.R.color.black, ShadowMockMediaPlayer.sResId);
+ mShadowMediaPlayer = (ShadowMediaPlayer) Shadows.shadowOf(mView.mMediaPlayer);
+
+ assertThat(mShadowMediaPlayer.getSourceUri().toString())
+ .isEqualTo("android.resource://com.android.setupwizardlib/"
+ + android.R.color.black);
+ }
+
+ @Test
+ public void prepareVideo_shouldSetAspectRatio() {
+ createDefaultView();
+
+ mShadowMediaPlayer.setVideoSize(720, 1280);
+
+ Robolectric.flushForegroundThreadScheduler();
+ mView.start();
+
+ mView.measure(View.MeasureSpec.makeMeasureSpec(720, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(720, View.MeasureSpec.EXACTLY));
+
+ final float aspectRatio = (float) mView.getMeasuredHeight() / mView.getMeasuredWidth();
+ assertThat(aspectRatio).isWithin(0.001f).of(1280f / 720f);
+ }
+
+ @Test
+ public void prepareVideo_zeroHeight_shouldSetAspectRatioToZero() {
+ createDefaultView();
+
+ mShadowMediaPlayer.setVideoSize(720, 0);
+
+ Robolectric.flushForegroundThreadScheduler();
+ mView.start();
+
+ final float aspectRatio = (float) mView.getHeight() / mView.getWidth();
+ assertThat(aspectRatio).isEqualTo(0.0f);
+ }
+
+ @Test
+ public void setVideoResId_resetDiffVideoResFromDiffPackage_videoResShouldBeSet() {
+ // VideoRes default set as android.R.color.white with
+ // default package(com.android.setupwizardlib)
+ createDefaultView();
+
+ // reset different videoRes from different package
+ String newPackageName = "com.android.fakepackage";
+ @RawRes int black = android.R.color.black;
+ addMediaInfo(black, newPackageName);
+ mView.setVideoResource(black, newPackageName);
+
+ // should be reset to black with the new package
+ mShadowMediaPlayer = (ShadowMediaPlayer) Shadows.shadowOf(mView.mMediaPlayer);
+ assertThat(mShadowMediaPlayer.getSourceUri().toString())
+ .isEqualTo("android.resource://" + newPackageName + "/"
+ + android.R.color.black);
+ }
+
+ @Test
+ public void setVideoResId_resetDiffVideoResFromSamePackage_videoResShouldBeSet() {
+ // VideoRes default set as android.R.color.white with
+ // default package(com.android.setupwizardlib)
+ createDefaultView();
+
+ // reset different videoRes from the same package(default package)
+ String defaultPackageName = "com.android.setupwizardlib";
+ @RawRes int black = android.R.color.black;
+ addMediaInfo(black);
+ mView.setVideoResource(black, defaultPackageName);
+
+ // should be reset to black with the same package(default package)
+ mShadowMediaPlayer = (ShadowMediaPlayer) Shadows.shadowOf(mView.mMediaPlayer);
+ assertThat(mShadowMediaPlayer.getSourceUri().toString())
+ .isEqualTo("android.resource://" + defaultPackageName + "/"
+ + android.R.color.black);
+ }
+
+ @Test
+ public void setVideoResId_resetSameVideoResFromDifferentPackage_videoResShouldBeSet() {
+ // VideoRes default set as android.R.color.white with
+ // default package(com.android.setupwizardlib)
+ createDefaultView();
+
+
+ // reset same videoRes from different package
+ @RawRes int white = android.R.color.white;
+ String newPackageName = "com.android.fakepackage";
+ addMediaInfo(white, newPackageName);
+ mView.setVideoResource(white, newPackageName);
+
+ // should be white with the new package
+ mShadowMediaPlayer = (ShadowMediaPlayer) Shadows.shadowOf(mView.mMediaPlayer);
+ assertThat(mShadowMediaPlayer.getSourceUri().toString())
+ .isEqualTo("android.resource://" + newPackageName + "/"
+ + android.R.color.white);
}
private void createDefaultView() {
mView = new IllustrationVideoView(
application,
Robolectric.buildAttributeSet()
- // Any resource attribute should work, since the media player is mocked
+ // Any resource attribute should work, since the DataSource is fake
.addAttribute(R.attr.suwVideo, "@android:color/white")
.build());
+
+ Activity activity = Robolectric.setupActivity(Activity.class);
+ activity.setContentView(mView);
+ setWindowVisible();
+
+ mView.setSurfaceTexture(mock(SurfaceTexture.class));
mView.onSurfaceTextureAvailable(mSurfaceTexture, 500, 500);
+ mShadowMediaPlayer = (ShadowMediaPlayer) Shadows.shadowOf(mView.mMediaPlayer);
+ mShadowMediaPlayer.setInvalidStateBehavior(InvalidStateBehavior.EMULATE);
}
- @Implements(MediaPlayer.class)
- public static class ShadowMockMediaPlayer extends ShadowMediaPlayer {
+ private void setWindowVisible() {
+ Object viewRootImpl = ReflectionHelpers.callInstanceMethod(mView, "getViewRootImpl");
+ ReflectionHelpers.callInstanceMethod(
+ viewRootImpl,
+ "handleAppVisibility",
+ ClassParameter.from(boolean.class, true));
+ assertThat(mView.isAttachedToWindow()).isTrue();
+ assertThat(mView.getWindowVisibility()).isEqualTo(View.VISIBLE);
+ }
- private static MediaPlayer sMediaPlayer = mock(MediaPlayer.class);
- private static int sResId;
+ private void addMediaInfo(@RawRes int res) {
+ ShadowMediaPlayer.addMediaInfo(
+ DataSource.toDataSource(
+ application,
+ Uri.parse("android.resource://com.android.setupwizardlib/" + res),
+ null),
+ new MediaInfo(5000, 1));
+ }
- public static void reset() {
- sMediaPlayer = mock(MediaPlayer.class);
- sResId = 0;
- }
-
- @Implementation
- public static MediaPlayer create(Context context, int resId) {
- sResId = resId;
- return sMediaPlayer;
- }
-
- public static MediaPlayer getMock() {
- return sMediaPlayer;
- }
+ private void addMediaInfo(@RawRes int res, String packageName) {
+ ShadowMediaPlayer.addMediaInfo(
+ DataSource.toDataSource(
+ application,
+ Uri.parse("android.resource://" + packageName + "/" + res),
+ null),
+ new MediaInfo(5000, 1));
}
@Implements(Surface.class)
@@ -181,6 +301,7 @@
@RealObject
private Surface mRealSurface;
+ @Override
public void __constructor__(SurfaceTexture surfaceTexture) {
// Call the constructor on the real object, so that critical fields such as mLock is
// initialized properly.
diff --git a/navigationbar/res/values-as/strings.xml b/navigationbar/res/values-as/strings.xml
new file mode 100644
index 0000000..398ff1f
--- /dev/null
+++ b/navigationbar/res/values-as/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"পৰৱৰ্তী"</string>
+ <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"উভতি যাওক"</string>
+</resources>
diff --git a/navigationbar/res/values-or/strings.xml b/navigationbar/res/values-or/strings.xml
new file mode 100644
index 0000000..4c70d06
--- /dev/null
+++ b/navigationbar/res/values-or/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"ପରବର୍ତ୍ତୀ"</string>
+ <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"ପଛକୁ ଫେରନ୍ତୁ"</string>
+</resources>
diff --git a/tools/build_for_build_server.sh b/tools/build_for_build_server.sh
index 7a8c942..1ed4ea7 100755
--- a/tools/build_for_build_server.sh
+++ b/tools/build_for_build_server.sh
@@ -6,4 +6,4 @@
export TARGET_BUILD_TYPE="release"
export TARGET_BUILD_APPS="setup-wizard-lib"
-./gradlew buildProjectFull test coverage
+./gradlew buildProjectFull test coverage --info