blob: fd05b8ed92b1e97b436da9da495b8afff734add3 [file] [log] [blame]
/*
* 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 android.support.v17.leanback.widget;
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.v17.leanback.R;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
/**
* GuidanceStylist is used within a {@link android.support.v17.leanback.app.GuidedStepFragment}
* to display contextual information for the decision(s) required at that step.
* <p>
* Many aspects of the base GuidanceStylist can be customized through theming; see the theme
* attributes below. Note that these attributes are not set on individual elements in layout
* XML, but instead would be set in a custom theme. See
* <a href="http://developer.android.com/guide/topics/ui/themes.html">Styles and Themes</a>
* for more information.
* <p>
* If these hooks are insufficient, this class may also be subclassed. Subclasses
* may wish to override the {@link #onProvideLayoutId} method to change the layout file used to
* display the guidance; more complex layouts may be supported by also providing a subclass of
* {@link GuidanceStylist.Guidance} with extra fields.
* <p>
* Note: If an alternate layout is provided, the following view IDs should be used to refer to base
* elements:
* <ul>
* <li>{@link android.support.v17.leanback.R.id#guidance_title}</li>
* <li>{@link android.support.v17.leanback.R.id#guidance_description}</li>
* <li>{@link android.support.v17.leanback.R.id#guidance_breadcrumb}</li>
* <li>{@link android.support.v17.leanback.R.id#guidance_icon}</li>
* </ul><p>
* View IDs are allowed to be missing, in which case the corresponding views will be null.
*
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepImeAppearingAnimation
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepImeDisappearingAnimation
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceContainerStyle
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceTitleStyle
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceDescriptionStyle
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceBreadcrumbStyle
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceIconStyle
* @see android.support.v17.leanback.app.GuidedStepFragment
* @see GuidanceStylist.Guidance
*/
public class GuidanceStylist implements FragmentAnimationProvider {
/**
* A data class representing contextual information for a {@link
* android.support.v17.leanback.app.GuidedStepFragment}. Guidance consists of a short title,
* a longer description, a breadcrumb to help with global navigation (often indicating where
* the back button will lead), and an optional icon. All this information is intended to
* provide users with the appropriate context to make the decision(s) required by the current
* step.
* <p>
* Clients may provide a subclass of this if they wish to remember auxiliary data for use in
* a customized GuidanceStylist.
*/
public static class Guidance {
private final String mTitle;
private final String mDescription;
private final String mBreadcrumb;
private final Drawable mIconDrawable;
/**
* Constructs a Guidance object with the specified title, description, breadcrumb, and
* icon drawable.
* @param title The title for the current guided step.
* @param description The description for the current guided step.
* @param breadcrumb The breadcrumb for the current guided step.
* @param icon The icon drawable representing the current guided step.
*/
public Guidance(String title, String description, String breadcrumb, Drawable icon) {
mBreadcrumb = breadcrumb;
mTitle = title;
mDescription = description;
mIconDrawable = icon;
}
/**
* Returns the title specified when this Guidance was constructed.
* @return The title for this Guidance.
*/
public String getTitle() {
return mTitle;
}
/**
* Returns the description specified when this Guidance was constructed.
* @return The description for this Guidance.
*/
public String getDescription() {
return mDescription;
}
/**
* Returns the breadcrumb specified when this Guidance was constructed.
* @return The breadcrumb for this Guidance.
*/
public String getBreadcrumb() {
return mBreadcrumb;
}
/**
* Returns the icon drawable specified when this Guidance was constructed.
* @return The icon for this Guidance.
*/
public Drawable getIconDrawable() {
return mIconDrawable;
}
}
private TextView mTitleView;
private TextView mDescriptionView;
private TextView mBreadcrumbView;
private ImageView mIconView;
/**
* Creates an appropriately configured view for the given Guidance, using the provided
* inflater and container.
* <p>
* <i>Note: Does not actually add the created view to the container; the caller should do
* this.</i>
* @param inflater The layout inflater to be used when constructing the view.
* @param container The view group to be passed in the call to
* <code>LayoutInflater.inflate</code>.
* @param guidance The guidance data for the view.
* @return The view to be added to the caller's view hierarchy.
*/
public View onCreateView(LayoutInflater inflater, ViewGroup container, Guidance guidance) {
View guidanceView = inflater.inflate(onProvideLayoutId(), container, false);
mTitleView = (TextView) guidanceView.findViewById(R.id.guidance_title);
mBreadcrumbView = (TextView) guidanceView.findViewById(R.id.guidance_breadcrumb);
mDescriptionView = (TextView) guidanceView.findViewById(R.id.guidance_description);
mIconView = (ImageView) guidanceView.findViewById(R.id.guidance_icon);
// We allow any of the cached subviews to be null, so that subclasses can choose not to
// display a particular piece of information.
if (mTitleView != null) {
mTitleView.setText(guidance.getTitle());
}
if (mBreadcrumbView != null) {
mBreadcrumbView.setText(guidance.getBreadcrumb());
}
if (mDescriptionView != null) {
mDescriptionView.setText(guidance.getDescription());
}
if (mIconView != null) {
mIconView.setImageDrawable(guidance.getIconDrawable());
}
return guidanceView;
}
/**
* Provides the resource ID of the layout defining the guidance view. Subclasses may override
* to provide their own customized layouts. The base implementation returns
* {@link android.support.v17.leanback.R.layout#lb_guidance}. If overridden, the substituted
* layout should contain matching IDs for any views that should be managed by the base class;
* this can be achieved by starting with a copy of the base layout file.
* @return The resource ID of the layout to be inflated to define the guidance view.
*/
public int onProvideLayoutId() {
return R.layout.lb_guidance;
}
/**
* Returns the view displaying the title of the guidance.
* @return The text view object for the title.
*/
public TextView getTitleView() {
return mTitleView;
}
/**
* Returns the view displaying the description of the guidance.
* @return The text view object for the description.
*/
public TextView getDescriptionView() {
return mDescriptionView;
}
/**
* Returns the view displaying the breadcrumb of the guidance.
* @return The text view object for the breadcrumb.
*/
public TextView getBreadcrumbView() {
return mBreadcrumbView;
}
/**
* Returns the view displaying the icon of the guidance.
* @return The image view object for the icon.
*/
public ImageView getIconView() {
return mIconView;
}
/**
* {@inheritDoc}
*/
@Override
public void onImeAppearing(@NonNull List<Animator> animators) {
addAnimator(animators, mTitleView, R.attr.guidedStepImeAppearingAnimation);
addAnimator(animators, mBreadcrumbView, R.attr.guidedStepImeAppearingAnimation);
addAnimator(animators, mDescriptionView, R.attr.guidedStepImeAppearingAnimation);
addAnimator(animators, mIconView, R.attr.guidedStepImeAppearingAnimation);
}
/**
* {@inheritDoc}
*/
@Override
public void onImeDisappearing(@NonNull List<Animator> animators) {
addAnimator(animators, mTitleView, R.attr.guidedStepImeDisappearingAnimation);
addAnimator(animators, mBreadcrumbView, R.attr.guidedStepImeDisappearingAnimation);
addAnimator(animators, mDescriptionView, R.attr.guidedStepImeDisappearingAnimation);
addAnimator(animators, mIconView, R.attr.guidedStepImeDisappearingAnimation);
}
private void addAnimator(List<Animator> animators, View v, int attrId) {
if (v != null) {
Context ctx = v.getContext();
TypedValue typedValue = new TypedValue();
ctx.getTheme().resolveAttribute(attrId, typedValue, true);
Animator animator = AnimatorInflater.loadAnimator(ctx, typedValue.resourceId);
animator.setTarget(v);
animators.add(animator);
}
}
}