1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 package androidx.leanback.widget; 15 16 import android.animation.Animator; 17 import android.graphics.drawable.Drawable; 18 import android.text.TextUtils; 19 import android.view.LayoutInflater; 20 import android.view.View; 21 import android.view.ViewGroup; 22 import android.widget.ImageView; 23 import android.widget.TextView; 24 25 import androidx.annotation.NonNull; 26 import androidx.leanback.R; 27 28 import java.util.List; 29 30 /** 31 * GuidanceStylist is used within a {@link androidx.leanback.app.GuidedStepFragment} 32 * to display contextual information for the decision(s) required at that step. 33 * <p> 34 * Many aspects of the base GuidanceStylist can be customized through theming; see the theme 35 * attributes below. Note that these attributes are not set on individual elements in layout 36 * XML, but instead would be set in a custom theme. See 37 * <a href="http://developer.android.com/guide/topics/ui/themes.html">Styles and Themes</a> 38 * for more information. 39 * <p> 40 * If these hooks are insufficient, this class may also be subclassed. Subclasses 41 * may wish to override the {@link #onProvideLayoutId} method to change the layout file used to 42 * display the guidance; more complex layouts may be supported by also providing a subclass of 43 * {@link GuidanceStylist.Guidance} with extra fields. 44 * <p> 45 * Note: If an alternate layout is provided, the following view IDs should be used to refer to base 46 * elements: 47 * <ul> 48 * <li>{@link androidx.leanback.R.id#guidance_title}</li> 49 * <li>{@link androidx.leanback.R.id#guidance_description}</li> 50 * <li>{@link androidx.leanback.R.id#guidance_breadcrumb}</li> 51 * <li>{@link androidx.leanback.R.id#guidance_icon}</li> 52 * </ul><p> 53 * View IDs are allowed to be missing, in which case the corresponding views will be null. 54 * 55 * @attr ref androidx.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepImeAppearingAnimation 56 * @attr ref androidx.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepImeDisappearingAnimation 57 * @attr ref androidx.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceContainerStyle 58 * @attr ref androidx.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceTitleStyle 59 * @attr ref androidx.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceDescriptionStyle 60 * @attr ref androidx.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceBreadcrumbStyle 61 * @attr ref androidx.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceIconStyle 62 * @see androidx.leanback.app.GuidedStepFragment 63 * @see GuidanceStylist.Guidance 64 */ 65 public class GuidanceStylist implements FragmentAnimationProvider { 66 67 /** 68 * A data class representing contextual information for a {@link 69 * androidx.leanback.app.GuidedStepFragment}. Guidance consists of a short title, 70 * a longer description, a breadcrumb to help with global navigation (often indicating where 71 * the back button will lead), and an optional icon. All this information is intended to 72 * provide users with the appropriate context to make the decision(s) required by the current 73 * step. 74 * <p> 75 * Clients may provide a subclass of this if they wish to remember auxiliary data for use in 76 * a customized GuidanceStylist. 77 */ 78 public static class Guidance { 79 private final String mTitle; 80 private final String mDescription; 81 private final String mBreadcrumb; 82 private final Drawable mIconDrawable; 83 84 /** 85 * Constructs a Guidance object with the specified title, description, breadcrumb, and 86 * icon drawable. 87 * @param title The title for the current guided step. 88 * @param description The description for the current guided step. 89 * @param breadcrumb The breadcrumb for the current guided step. 90 * @param icon The icon drawable representing the current guided step. 91 */ Guidance(String title, String description, String breadcrumb, Drawable icon)92 public Guidance(String title, String description, String breadcrumb, Drawable icon) { 93 mBreadcrumb = breadcrumb; 94 mTitle = title; 95 mDescription = description; 96 mIconDrawable = icon; 97 } 98 99 /** 100 * Returns the title specified when this Guidance was constructed. 101 * @return The title for this Guidance. 102 */ getTitle()103 public String getTitle() { 104 return mTitle; 105 } 106 107 /** 108 * Returns the description specified when this Guidance was constructed. 109 * @return The description for this Guidance. 110 */ getDescription()111 public String getDescription() { 112 return mDescription; 113 } 114 115 /** 116 * Returns the breadcrumb specified when this Guidance was constructed. 117 * @return The breadcrumb for this Guidance. 118 */ getBreadcrumb()119 public String getBreadcrumb() { 120 return mBreadcrumb; 121 } 122 123 /** 124 * Returns the icon drawable specified when this Guidance was constructed. 125 * @return The icon for this Guidance. 126 */ getIconDrawable()127 public Drawable getIconDrawable() { 128 return mIconDrawable; 129 } 130 } 131 132 private TextView mTitleView; 133 private TextView mDescriptionView; 134 private TextView mBreadcrumbView; 135 private ImageView mIconView; 136 private View mGuidanceContainer; 137 138 /** 139 * Creates an appropriately configured view for the given Guidance, using the provided 140 * inflater and container. 141 * <p> 142 * <i>Note: Does not actually add the created view to the container; the caller should do 143 * this.</i> 144 * @param inflater The layout inflater to be used when constructing the view. 145 * @param container The view group to be passed in the call to 146 * <code>LayoutInflater.inflate</code>. 147 * @param guidance The guidance data for the view. 148 * @return The view to be added to the caller's view hierarchy. 149 */ onCreateView( final LayoutInflater inflater, ViewGroup container, Guidance guidance)150 public View onCreateView( 151 final LayoutInflater inflater, ViewGroup container, Guidance guidance) { 152 153 View guidanceView = inflater.inflate(onProvideLayoutId(), container, false); 154 mTitleView = (TextView) guidanceView.findViewById(R.id.guidance_title); 155 mBreadcrumbView = (TextView) guidanceView.findViewById(R.id.guidance_breadcrumb); 156 mDescriptionView = (TextView) guidanceView.findViewById(R.id.guidance_description); 157 mIconView = (ImageView) guidanceView.findViewById(R.id.guidance_icon); 158 mGuidanceContainer = guidanceView.findViewById(R.id.guidance_container); 159 160 // We allow any of the cached subviews to be null, so that subclasses can choose not to 161 // display a particular piece of information. 162 if (mTitleView != null) { 163 mTitleView.setText(guidance.getTitle()); 164 } 165 166 if (mBreadcrumbView != null) { 167 mBreadcrumbView.setText(guidance.getBreadcrumb()); 168 } 169 170 if (mDescriptionView != null) { 171 mDescriptionView.setText(guidance.getDescription()); 172 } 173 174 if (mIconView != null) { 175 if (guidance.getIconDrawable() != null) { 176 mIconView.setImageDrawable(guidance.getIconDrawable()); 177 } else { 178 mIconView.setVisibility(View.GONE); 179 } 180 } 181 182 if (mGuidanceContainer != null) { 183 CharSequence contentDescription = mGuidanceContainer.getContentDescription(); 184 if (TextUtils.isEmpty(contentDescription)) { 185 StringBuilder builder = new StringBuilder(); 186 if (!TextUtils.isEmpty(guidance.getBreadcrumb())) { 187 builder.append(guidance.getBreadcrumb()).append('\n'); 188 } 189 if (!TextUtils.isEmpty(guidance.getTitle())) { 190 builder.append(guidance.getTitle()).append('\n'); 191 } 192 if (!TextUtils.isEmpty(guidance.getDescription())) { 193 builder.append(guidance.getDescription()).append('\n'); 194 } 195 mGuidanceContainer.setContentDescription(builder); 196 } 197 } 198 199 return guidanceView; 200 } 201 202 /** 203 * Called when destroy the View created by GuidanceStylist. 204 */ onDestroyView()205 public void onDestroyView() { 206 mBreadcrumbView = null; 207 mDescriptionView = null; 208 mIconView = null; 209 mTitleView = null; 210 } 211 212 /** 213 * Provides the resource ID of the layout defining the guidance view. Subclasses may override 214 * to provide their own customized layouts. The base implementation returns 215 * {@link androidx.leanback.R.layout#lb_guidance}. If overridden, the substituted 216 * layout should contain matching IDs for any views that should be managed by the base class; 217 * this can be achieved by starting with a copy of the base layout file. 218 * @return The resource ID of the layout to be inflated to define the guidance view. 219 */ onProvideLayoutId()220 public int onProvideLayoutId() { 221 return R.layout.lb_guidance; 222 } 223 224 /** 225 * Returns the view displaying the title of the guidance. 226 * @return The text view object for the title. 227 */ getTitleView()228 public TextView getTitleView() { 229 return mTitleView; 230 } 231 232 /** 233 * Returns the view displaying the description of the guidance. 234 * @return The text view object for the description. 235 */ getDescriptionView()236 public TextView getDescriptionView() { 237 return mDescriptionView; 238 } 239 240 /** 241 * Returns the view displaying the breadcrumb of the guidance. 242 * @return The text view object for the breadcrumb. 243 */ getBreadcrumbView()244 public TextView getBreadcrumbView() { 245 return mBreadcrumbView; 246 } 247 248 /** 249 * Returns the view displaying the icon of the guidance. 250 * @return The image view object for the icon. 251 */ getIconView()252 public ImageView getIconView() { 253 return mIconView; 254 } 255 256 /** 257 * {@inheritDoc} 258 */ 259 @Override onImeAppearing(@onNull List<Animator> animators)260 public void onImeAppearing(@NonNull List<Animator> animators) { 261 } 262 263 /** 264 * {@inheritDoc} 265 */ 266 @Override onImeDisappearing(@onNull List<Animator> animators)267 public void onImeDisappearing(@NonNull List<Animator> animators) { 268 } 269 270 } 271