Adding support for app icon in OnboardingFragment.
Also, allowing developers to customize default enter animations.
Change-Id: Ifdd9a1132eab0888e3abc6861a0579f3d370ae15
diff --git a/api/current.txt b/api/current.txt
index c13cc1e..c9295673 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1814,36 +1814,44 @@
public abstract class OnboardingFragment extends android.app.Fragment {
ctor public OnboardingFragment();
method protected final int getCurrentPageIndex();
+ method public final int getIconResourceId();
method public final int getLogoResourceId();
method protected abstract int getPageCount();
method protected abstract java.lang.CharSequence getPageDescription(int);
method protected abstract java.lang.CharSequence getPageTitle(int);
method protected abstract android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup);
method protected abstract android.view.View onCreateContentView(android.view.LayoutInflater, android.view.ViewGroup);
+ method protected android.animation.Animator onCreateDescriptionAnimator();
method protected android.animation.Animator onCreateEnterAnimation();
method protected abstract android.view.View onCreateForegroundView(android.view.LayoutInflater, android.view.ViewGroup);
method protected android.animation.Animator onCreateLogoAnimation();
+ method protected android.animation.Animator onCreateTitleAnimator();
method protected void onFinishFragment();
method protected void onPageChanged(int, int);
method public int onProvideTheme();
+ method public final void setIconResouceId(int);
method public final void setLogoResourceId(int);
}
public abstract class OnboardingSupportFragment extends android.support.v4.app.Fragment {
ctor public OnboardingSupportFragment();
method protected final int getCurrentPageIndex();
+ method public final int getIconResourceId();
method public final int getLogoResourceId();
method protected abstract int getPageCount();
method protected abstract java.lang.CharSequence getPageDescription(int);
method protected abstract java.lang.CharSequence getPageTitle(int);
method protected abstract android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup);
method protected abstract android.view.View onCreateContentView(android.view.LayoutInflater, android.view.ViewGroup);
+ method protected android.animation.Animator onCreateDescriptionAnimator();
method protected android.animation.Animator onCreateEnterAnimation();
method protected abstract android.view.View onCreateForegroundView(android.view.LayoutInflater, android.view.ViewGroup);
method protected android.animation.Animator onCreateLogoAnimation();
+ method protected android.animation.Animator onCreateTitleAnimator();
method protected void onFinishFragment();
method protected void onPageChanged(int, int);
method public int onProvideTheme();
+ method public final void setIconResouceId(int);
method public final void setLogoResourceId(int);
}
diff --git a/v17/leanback/res/animator/lb_onboarding_description_enter.xml b/v17/leanback/res/animator/lb_onboarding_description_enter.xml
index 5f26cdd..3cb5843 100644
--- a/v17/leanback/res/animator/lb_onboarding_description_enter.xml
+++ b/v17/leanback/res/animator/lb_onboarding_description_enter.xml
@@ -21,11 +21,13 @@
android:valueFrom="0.0"
android:valueTo="1.0"
android:duration="533"
+ android:startOffset="@integer/lb_onboarding_header_description_delay"
android:interpolator="@android:interpolator/fast_out_slow_in" />
<objectAnimator
android:propertyName="translationY"
android:valueFrom="60dp"
android:valueTo="0dp"
android:duration="533"
+ android:startOffset="@integer/lb_onboarding_header_description_delay"
android:interpolator="@android:interpolator/fast_out_slow_in" />
</set>
diff --git a/v17/leanback/res/animator/lb_onboarding_title_enter.xml b/v17/leanback/res/animator/lb_onboarding_title_enter.xml
index 5f26cdd..9b65b48 100644
--- a/v17/leanback/res/animator/lb_onboarding_title_enter.xml
+++ b/v17/leanback/res/animator/lb_onboarding_title_enter.xml
@@ -21,11 +21,13 @@
android:valueFrom="0.0"
android:valueTo="1.0"
android:duration="533"
+ android:startOffset="@integer/lb_onboarding_header_title_delay"
android:interpolator="@android:interpolator/fast_out_slow_in" />
<objectAnimator
android:propertyName="translationY"
android:valueFrom="60dp"
android:valueTo="0dp"
android:duration="533"
+ android:startOffset="@integer/lb_onboarding_header_title_delay"
android:interpolator="@android:interpolator/fast_out_slow_in" />
</set>
diff --git a/v17/leanback/res/layout/lb_onboarding_fragment.xml b/v17/leanback/res/layout/lb_onboarding_fragment.xml
index 04bd0ea..823fe74 100644
--- a/v17/leanback/res/layout/lb_onboarding_fragment.xml
+++ b/v17/leanback/res/layout/lb_onboarding_fragment.xml
@@ -28,10 +28,15 @@
android:layout_height="match_parent"
android:visibility="gone" />
+ <ImageView
+ android:id="@+id/main_icon"
+ style="?attr/onboardingMainIconStyle"/>
+
<LinearLayout
android:id="@+id/page_container"
style="?attr/onboardingHeaderStyle"
android:visibility="gone">
+
<TextView
android:id="@+id/title"
style="?attr/onboardingTitleStyle"/>
diff --git a/v17/leanback/res/values/attrs.xml b/v17/leanback/res/values/attrs.xml
index 870d958..26c5ef7 100644
--- a/v17/leanback/res/values/attrs.xml
+++ b/v17/leanback/res/values/attrs.xml
@@ -559,6 +559,10 @@
<!-- Theme attribute for the style of the logo in onboarding screen. Default is
{@link android.support.v17.leanback.R.style#Widget_Leanback_OnboardingLogoStyle}.-->
<attr name="onboardingLogoStyle" format="reference" />
+
+ <!-- Theme attribute for the style of the main icon in onboarding fragment. Default is
+ {@link android.support.v17.leanback.R.style#Widget_Leanback_OnboardingMainIconStyle}.-->
+ <attr name="onboardingMainIconStyle" format="reference" />
</declare-styleable>
<declare-styleable name="PagingIndicator">
diff --git a/v17/leanback/res/values/integers.xml b/v17/leanback/res/values/integers.xml
index c9f3384..b8bdb18 100644
--- a/v17/leanback/res/values/integers.xml
+++ b/v17/leanback/res/values/integers.xml
@@ -29,6 +29,8 @@
<integer name="lb_playback_rows_fade_out_ms">250</integer>
<integer name="lb_playback_rows_fade_delay_ms">100</integer>
<integer name="lb_playback_controls_show_time_ms">3000</integer>
+ <integer name="lb_onboarding_header_title_delay">33</integer>
+ <integer name="lb_onboarding_header_description_delay">33</integer>
<!-- Gravity.LEFT -->
<integer name="slideEdgeStart">3</integer>
diff --git a/v17/leanback/res/values/styles.xml b/v17/leanback/res/values/styles.xml
index dbe090a..d10260d 100644
--- a/v17/leanback/res/values/styles.xml
+++ b/v17/leanback/res/values/styles.xml
@@ -778,4 +778,15 @@
<item name="android:contentDescription">@null</item>
</style>
+ <!-- Styles for the main icon in OnboardingFragment. -->
+ <style name="Widget.Leanback.OnboardingMainIconStyle">
+ <item name="android:layout_width">64dp</item>
+ <item name="android:layout_height">64dp</item>
+ <item name="android:layout_above">@id/page_container</item>
+ <item name="android:layout_centerHorizontal">true</item>
+ <item name="android:layout_marginBottom">16dp</item>
+ <item name="android:contentDescription">@null</item>
+ <item name="android:visibility">gone</item>
+ </style>
+
</resources>
diff --git a/v17/leanback/res/values/themes.xml b/v17/leanback/res/values/themes.xml
index c6d6baa..e5b98f6 100644
--- a/v17/leanback/res/values/themes.xml
+++ b/v17/leanback/res/values/themes.xml
@@ -213,6 +213,7 @@
<item name="onboardingPageIndicatorStyle">@style/Widget.Leanback.OnboardingPageIndicatorStyle</item>
<item name="onboardingStartButtonStyle">@style/Widget.Leanback.OnboardingStartButtonStyle</item>
<item name="onboardingLogoStyle">@style/Widget.Leanback.OnboardingLogoStyle</item>
+ <item name="onboardingMainIconStyle">@style/Widget.Leanback.OnboardingMainIconStyle</item>
</style>
</resources>
diff --git a/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java b/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
index 0459ab6..d67cdf2 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
@@ -53,8 +53,8 @@
* <p>
* <h3>Building the screen</h3>
* The view structure of onboarding screen is composed of the common parts and custom parts. The
- * common parts are composed of title, description and page navigator and the custom parts are
- * composed of background, contents and foreground.
+ * common parts are composed of icon, title, description and page navigator and the custom parts
+ * are composed of background, contents and foreground.
* <p>
* To build the screen views, the inherited class should override:
* <ul>
@@ -102,8 +102,12 @@
* If the inherited class provides neither the logo image nor the animation, the logo animation will
* be omitted.
* <h4>Page enter animation</h4>
- * After logo animation finishes, page enter animation starts. The application can provide the
- * animations of custom views by overriding {@link #onCreateEnterAnimation}.
+ * After logo animation finishes, page enter animation starts, which causes the header section -
+ * title and description views to fade and slide in. Users can override the default
+ * fade + slide animation by overriding {@link #onCreateTitleAnimator()} &
+ * {@link #onCreateDescriptionAnimator()}. By default we don't animate the custom views but users
+ * can provide animation by overriding {@link #onCreateEnterAnimation}.
+ *
* <h4>Page change animation</h4>
* When the page changes, the default animations of the title and description are played. The
* inherited class can override {@link #onPageChanged} to start the custom animations.
@@ -149,8 +153,6 @@
private static final boolean DEBUG = false;
private static final long LOGO_SPLASH_PAUSE_DURATION_MS = 1333;
- private static final long START_DELAY_TITLE_MS = 33;
- private static final long START_DELAY_DESCRIPTION_MS = 33;
private static final long HEADER_ANIMATION_DURATION_MS = 417;
private static final long DESCRIPTION_START_DELAY_MS = 33;
@@ -171,6 +173,10 @@
PagingIndicator mPageIndicator;
View mStartButton;
private ImageView mLogoView;
+ // Optional icon that can be displayed on top of the header section.
+ private ImageView mMainIconView;
+ private int mIconResourceId;
+
TextView mTitleView;
TextView mDescriptionView;
@@ -264,6 +270,7 @@
mStartButton = view.findViewById(R.id.button_start);
mStartButton.setOnClickListener(mOnClickListener);
mStartButton.setOnKeyListener(mOnKeyListener);
+ mMainIconView = (ImageView) view.findViewById(R.id.main_icon);
mLogoView = (ImageView) view.findViewById(R.id.logo);
mTitleView = (TextView) view.findViewById(R.id.title);
mDescriptionView = (TextView) view.findViewById(R.id.description);
@@ -410,6 +417,12 @@
private void initializeViews(View container) {
mLogoView.setVisibility(View.GONE);
+
+ if (mIconResourceId != 0) {
+ mMainIconView.setImageResource(mIconResourceId);
+ mMainIconView.setVisibility(View.VISIBLE);
+ }
+
// Create custom views.
LayoutInflater inflater = getThemeInflater(LayoutInflater.from(getActivity()));
ViewGroup backgroundContainer = (ViewGroup) container.findViewById(
@@ -457,27 +470,31 @@
R.animator.lb_onboarding_page_indicator_enter);
animator.setTarget(getPageCount() <= 1 ? mStartButton : mPageIndicator);
animators.add(animator);
- // Header title
- View view = getActivity().findViewById(R.id.title);
- view.setAlpha(0);
- animator = AnimatorInflater.loadAnimator(getActivity(),
- R.animator.lb_onboarding_title_enter);
- animator.setStartDelay(START_DELAY_TITLE_MS);
- animator.setTarget(view);
- animators.add(animator);
- // Header description
- view = getActivity().findViewById(R.id.description);
- view.setAlpha(0);
- animator = AnimatorInflater.loadAnimator(getActivity(),
- R.animator.lb_onboarding_description_enter);
- animator.setStartDelay(START_DELAY_DESCRIPTION_MS);
- animator.setTarget(view);
- animators.add(animator);
+
+ animator = onCreateTitleAnimator();
+ if (animator != null) {
+ // Header title.
+ animator.setTarget(mTitleView);
+ animators.add(animator);
+ }
+
+ animator = onCreateDescriptionAnimator();
+ if (animator != null) {
+ // Header description.
+ animator.setTarget(mDescriptionView);
+ animators.add(animator);
+ }
+
// Customized animation by the inherited class.
Animator customAnimator = onCreateEnterAnimation();
if (customAnimator != null) {
animators.add(customAnimator);
}
+
+ // Return if we don't have any animations.
+ if (animators.isEmpty()) {
+ return;
+ }
mAnimator = new AnimatorSet();
mAnimator.playTogether(animators);
mAnimator.start();
@@ -486,6 +503,24 @@
}
/**
+ * Provides the entry animation for description view. This allows users to override the
+ * default fade and slide animation. Returning null will disable the animation.
+ */
+ protected Animator onCreateDescriptionAnimator() {
+ return AnimatorInflater.loadAnimator(getActivity(),
+ R.animator.lb_onboarding_description_enter);
+ }
+
+ /**
+ * Provides the entry animation for title view. This allows users to override the
+ * default fade and slide animation. Returning null will disable the animation.
+ */
+ protected Animator onCreateTitleAnimator() {
+ return AnimatorInflater.loadAnimator(getActivity(),
+ R.animator.lb_onboarding_title_enter);
+ }
+
+ /**
* Returns the page count.
*
* @return The page count.
@@ -690,4 +725,22 @@
}
return animator;
}
+
+ /**
+ * Sets the resource id for the main icon.
+ */
+ public final void setIconResouceId(int resourceId) {
+ this.mIconResourceId = resourceId;
+ if (mMainIconView != null) {
+ mMainIconView.setImageResource(resourceId);
+ mMainIconView.setVisibility(View.VISIBLE);
+ }
+ }
+
+ /**
+ * Returns the resource id of the main icon.
+ */
+ public final int getIconResourceId() {
+ return mIconResourceId;
+ }
}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java
index 32163b0..75daf31 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java
@@ -56,8 +56,8 @@
* <p>
* <h3>Building the screen</h3>
* The view structure of onboarding screen is composed of the common parts and custom parts. The
- * common parts are composed of title, description and page navigator and the custom parts are
- * composed of background, contents and foreground.
+ * common parts are composed of icon, title, description and page navigator and the custom parts
+ * are composed of background, contents and foreground.
* <p>
* To build the screen views, the inherited class should override:
* <ul>
@@ -105,8 +105,12 @@
* If the inherited class provides neither the logo image nor the animation, the logo animation will
* be omitted.
* <h4>Page enter animation</h4>
- * After logo animation finishes, page enter animation starts. The application can provide the
- * animations of custom views by overriding {@link #onCreateEnterAnimation}.
+ * After logo animation finishes, page enter animation starts, which causes the header section -
+ * title and description views to fade and slide in. Users can override the default
+ * fade + slide animation by overriding {@link #onCreateTitleAnimator()} &
+ * {@link #onCreateDescriptionAnimator()}. By default we don't animate the custom views but users
+ * can provide animation by overriding {@link #onCreateEnterAnimation}.
+ *
* <h4>Page change animation</h4>
* When the page changes, the default animations of the title and description are played. The
* inherited class can override {@link #onPageChanged} to start the custom animations.
@@ -152,8 +156,6 @@
private static final boolean DEBUG = false;
private static final long LOGO_SPLASH_PAUSE_DURATION_MS = 1333;
- private static final long START_DELAY_TITLE_MS = 33;
- private static final long START_DELAY_DESCRIPTION_MS = 33;
private static final long HEADER_ANIMATION_DURATION_MS = 417;
private static final long DESCRIPTION_START_DELAY_MS = 33;
@@ -174,6 +176,10 @@
PagingIndicator mPageIndicator;
View mStartButton;
private ImageView mLogoView;
+ // Optional icon that can be displayed on top of the header section.
+ private ImageView mMainIconView;
+ private int mIconResourceId;
+
TextView mTitleView;
TextView mDescriptionView;
@@ -267,6 +273,7 @@
mStartButton = view.findViewById(R.id.button_start);
mStartButton.setOnClickListener(mOnClickListener);
mStartButton.setOnKeyListener(mOnKeyListener);
+ mMainIconView = (ImageView) view.findViewById(R.id.main_icon);
mLogoView = (ImageView) view.findViewById(R.id.logo);
mTitleView = (TextView) view.findViewById(R.id.title);
mDescriptionView = (TextView) view.findViewById(R.id.description);
@@ -413,6 +420,12 @@
private void initializeViews(View container) {
mLogoView.setVisibility(View.GONE);
+
+ if (mIconResourceId != 0) {
+ mMainIconView.setImageResource(mIconResourceId);
+ mMainIconView.setVisibility(View.VISIBLE);
+ }
+
// Create custom views.
LayoutInflater inflater = getThemeInflater(LayoutInflater.from(getActivity()));
ViewGroup backgroundContainer = (ViewGroup) container.findViewById(
@@ -460,27 +473,31 @@
R.animator.lb_onboarding_page_indicator_enter);
animator.setTarget(getPageCount() <= 1 ? mStartButton : mPageIndicator);
animators.add(animator);
- // Header title
- View view = getActivity().findViewById(R.id.title);
- view.setAlpha(0);
- animator = AnimatorInflater.loadAnimator(getActivity(),
- R.animator.lb_onboarding_title_enter);
- animator.setStartDelay(START_DELAY_TITLE_MS);
- animator.setTarget(view);
- animators.add(animator);
- // Header description
- view = getActivity().findViewById(R.id.description);
- view.setAlpha(0);
- animator = AnimatorInflater.loadAnimator(getActivity(),
- R.animator.lb_onboarding_description_enter);
- animator.setStartDelay(START_DELAY_DESCRIPTION_MS);
- animator.setTarget(view);
- animators.add(animator);
+
+ animator = onCreateTitleAnimator();
+ if (animator != null) {
+ // Header title.
+ animator.setTarget(mTitleView);
+ animators.add(animator);
+ }
+
+ animator = onCreateDescriptionAnimator();
+ if (animator != null) {
+ // Header description.
+ animator.setTarget(mDescriptionView);
+ animators.add(animator);
+ }
+
// Customized animation by the inherited class.
Animator customAnimator = onCreateEnterAnimation();
if (customAnimator != null) {
animators.add(customAnimator);
}
+
+ // Return if we don't have any animations.
+ if (animators.isEmpty()) {
+ return;
+ }
mAnimator = new AnimatorSet();
mAnimator.playTogether(animators);
mAnimator.start();
@@ -489,6 +506,24 @@
}
/**
+ * Provides the entry animation for description view. This allows users to override the
+ * default fade and slide animation. Returning null will disable the animation.
+ */
+ protected Animator onCreateDescriptionAnimator() {
+ return AnimatorInflater.loadAnimator(getActivity(),
+ R.animator.lb_onboarding_description_enter);
+ }
+
+ /**
+ * Provides the entry animation for title view. This allows users to override the
+ * default fade and slide animation. Returning null will disable the animation.
+ */
+ protected Animator onCreateTitleAnimator() {
+ return AnimatorInflater.loadAnimator(getActivity(),
+ R.animator.lb_onboarding_title_enter);
+ }
+
+ /**
* Returns the page count.
*
* @return The page count.
@@ -693,4 +728,22 @@
}
return animator;
}
+
+ /**
+ * Sets the resource id for the main icon.
+ */
+ public final void setIconResouceId(int resourceId) {
+ this.mIconResourceId = resourceId;
+ if (mMainIconView != null) {
+ mMainIconView.setImageResource(resourceId);
+ mMainIconView.setVisibility(View.VISIBLE);
+ }
+ }
+
+ /**
+ * Returns the resource id of the main icon.
+ */
+ public final int getIconResourceId() {
+ return mIconResourceId;
+ }
}