GuidedActionsStylist.java revision ac07e9d12b10138d4a449522f7082a40f18861e2
1ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing/* 2ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Copyright (C) 2015 The Android Open Source Project 3ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * 4ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * in compliance with the License. You may obtain a copy of the License at 6ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * 7ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * http://www.apache.org/licenses/LICENSE-2.0 8ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * 9ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Unless required by applicable law or agreed to in writing, software distributed under the License 10ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * or implied. See the License for the specific language governing permissions and limitations under 12ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * the License. 13ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 14ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingpackage android.support.v17.leanback.widget; 15ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 16ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.animation.Animator; 17ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.animation.AnimatorInflater; 18ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.animation.AnimatorListenerAdapter; 19ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.animation.AnimatorSet; 20ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.animation.ObjectAnimator; 21ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.content.Context; 22ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.content.pm.PackageManager; 23ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.content.res.Resources; 24ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.content.res.TypedArray; 25ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.graphics.drawable.Drawable; 26ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.net.Uri; 27ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.support.annotation.NonNull; 28ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.support.v17.leanback.R; 29ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.support.v17.leanback.widget.VerticalGridView; 30ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.support.v7.widget.RecyclerView; 31ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.support.v7.widget.RecyclerView.ViewHolder; 32ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.text.TextUtils; 33ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.util.Log; 34ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.util.TypedValue; 35ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.view.animation.DecelerateInterpolator; 36ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.view.LayoutInflater; 37ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.view.View; 38ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.view.ViewGroup; 39ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.view.ViewGroup.LayoutParams; 40ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.view.ViewPropertyAnimator; 41ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.view.ViewTreeObserver; 42ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.view.WindowManager; 43ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesingimport android.widget.EditText; 44ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.widget.ImageView; 45ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.widget.TextView; 46ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 47ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport java.util.List; 48ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 49ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing/** 50a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * GuidedActionsStylist is used within a {@link android.support.v17.leanback.app.GuidedStepFragment} 51a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * to supply the right-side panel where users can take actions. It consists of a container for the 52a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * list of actions, and a stationary selector view that indicates visually the location of focus. 53ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <p> 54ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Many aspects of the base GuidedActionsStylist can be customized through theming; see the 55ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * theme attributes below. Note that these attributes are not set on individual elements in layout 56ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * XML, but instead would be set in a custom theme. See 57ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <a href="http://developer.android.com/guide/topics/ui/themes.html">Styles and Themes</a> 58ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * for more information. 59ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <p> 60ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * If these hooks are insufficient, this class may also be subclassed. Subclasses may wish to 61ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * override the {@link #onProvideLayoutId} method to change the layout used to display the 62ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * list container and selector, or the {@link #onProvideItemLayoutId} method to change the layout 63ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * used to display each action. 64ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <p> 65ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Note: If an alternate list layout is provided, the following view IDs must be supplied: 66ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <ul> 67ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <li>{@link android.support.v17.leanback.R.id#guidedactions_selector}</li> 68ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <li>{@link android.support.v17.leanback.R.id#guidedactions_list}</li> 69ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * </ul><p> 70ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * These view IDs must be present in order for the stylist to function. The list ID must correspond 71ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * to a {@link VerticalGridView} or subclass. 72ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <p> 73ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * If an alternate item layout is provided, the following view IDs should be used to refer to base 74ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * elements: 75ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <ul> 76ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <li>{@link android.support.v17.leanback.R.id#guidedactions_item_content}</li> 77ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <li>{@link android.support.v17.leanback.R.id#guidedactions_item_title}</li> 78ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <li>{@link android.support.v17.leanback.R.id#guidedactions_item_description}</li> 79ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <li>{@link android.support.v17.leanback.R.id#guidedactions_item_icon}</li> 80ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <li>{@link android.support.v17.leanback.R.id#guidedactions_item_checkmark}</li> 81ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <li>{@link android.support.v17.leanback.R.id#guidedactions_item_chevron}</li> 82ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * </ul><p> 83ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * These view IDs are allowed to be missing, in which case the corresponding views in {@link 84ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * GuidedActionsStylist.ViewHolder} will be null. 854158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing * <p> 864158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing * In order to support editable actions, the view associated with guidedactions_item_title should 874158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing * be a subclass of {@link android.widget.EditText}, and should satisfy the {@link 884158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing * ImeKeyMonitor} interface. 89ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * 904158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepEntryAnimation 914158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepExitAnimation 924158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepReentryAnimation 934158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepReturnAnimation 944158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepImeAppearingAnimation 954158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepImeDisappearingAnimation 96ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsEntryAnimation 97ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsSelectorShowAnimation 98ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsSelectorHideAnimation 99ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsContainerStyle 100ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsSelectorStyle 101ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsListStyle 102ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemContainerStyle 103ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemCheckmarkStyle 104ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemIconStyle 105ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemContentStyle 106ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemTitleStyle 107ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemDescriptionStyle 108ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemChevronStyle 109ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionCheckedAnimation 110ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionUncheckedAnimation 111ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionPressedAnimation 112ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionUnpressedAnimation 113ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionEnabledChevronAlpha 114ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionDisabledChevronAlpha 115ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionContentWidth 116ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionContentWidthNoIcon 117ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionTitleMinLines 118ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionTitleMaxLines 119ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionDescriptionMinLines 120ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionVerticalPadding 121ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @see android.support.v17.leanback.app.GuidedStepFragment 122ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @see GuidedAction 123ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 124ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingpublic class GuidedActionsStylist implements FragmentAnimationProvider { 125ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 126ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 127ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * ViewHolder caches information about the action item layouts' subviews. Subclasses of {@link 128ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * GuidedActionsStylist} may also wish to subclass this in order to add fields. 129ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @see GuidedAction 130ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 131ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public static class ViewHolder { 132ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 133ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public final View view; 134ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 135ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private View mContentView; 136ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private TextView mTitleView; 137ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private TextView mDescriptionView; 138ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private ImageView mIconView; 139ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private ImageView mCheckmarkView; 140ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private ImageView mChevronView; 141ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 142ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 143ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Constructs an ViewHolder and caches the relevant subviews. 144ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 145ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public ViewHolder(View v) { 146ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing view = v; 147ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 148ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mContentView = v.findViewById(R.id.guidedactions_item_content); 149ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mTitleView = (TextView) v.findViewById(R.id.guidedactions_item_title); 150ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mDescriptionView = (TextView) v.findViewById(R.id.guidedactions_item_description); 151ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mIconView = (ImageView) v.findViewById(R.id.guidedactions_item_icon); 152ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mCheckmarkView = (ImageView) v.findViewById(R.id.guidedactions_item_checkmark); 153ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mChevronView = (ImageView) v.findViewById(R.id.guidedactions_item_chevron); 154ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 155ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 156ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 157ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Returns the content view within this view holder's view, where title and description are 158ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * shown. 159ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 160ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public View getContentView() { 161ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return mContentView; 162ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 163ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 164ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 165ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Returns the title view within this view holder's view. 166ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 167ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public TextView getTitleView() { 168ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return mTitleView; 169ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 170ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 171ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 172ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing * Convenience method to return an editable version of the title, if possible, 173ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing * or null if the title view isn't an EditText. 174ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing */ 175ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing public EditText getEditableTitleView() { 176ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing return (mTitleView instanceof EditText) ? (EditText)mTitleView : null; 177ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing } 178ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing 179ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing /** 180ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Returns the description view within this view holder's view. 181ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 182ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public TextView getDescriptionView() { 183ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return mDescriptionView; 184ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 185ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 186ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 187ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Returns the icon view within this view holder's view. 188ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 189ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public ImageView getIconView() { 190ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return mIconView; 191ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 192ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 193ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 194ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Returns the checkmark view within this view holder's view. 195ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 196ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public ImageView getCheckmarkView() { 197ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return mCheckmarkView; 198ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 199ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 200ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 201ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Returns the chevron view within this view holder's view. 202ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 203ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public ImageView getChevronView() { 204ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return mChevronView; 205ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 206ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 207ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 208ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 209ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private static String TAG = "GuidedActionsStylist"; 210ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 211ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing protected View mMainView; 212ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing protected VerticalGridView mActionsGridView; 213ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing protected View mSelectorView; 214ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 215ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // Cached values from resources 216ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private float mEnabledChevronAlpha; 217ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private float mDisabledChevronAlpha; 218ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int mContentWidth; 219ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int mContentWidthNoIcon; 220ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int mTitleMinLines; 221ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int mTitleMaxLines; 222ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int mDescriptionMinLines; 223ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int mVerticalPadding; 224ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int mDisplayHeight; 225ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 226ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 227ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Creates a view appropriate for displaying a list of GuidedActions, using the provided 228ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * inflater and container. 229ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <p> 230ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <i>Note: Does not actually add the created view to the container; the caller should do 231ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * this.</i> 232ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param inflater The layout inflater to be used when constructing the view. 233ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param container The view group to be passed in the call to 234ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <code>LayoutInflater.inflate</code>. 235ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @return The view to be added to the caller's view hierarchy. 236ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 237ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public View onCreateView(LayoutInflater inflater, ViewGroup container) { 238ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mMainView = inflater.inflate(onProvideLayoutId(), container, false); 239ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mSelectorView = mMainView.findViewById(R.id.guidedactions_selector); 240ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (mMainView instanceof VerticalGridView) { 241ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mActionsGridView = (VerticalGridView) mMainView; 242ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } else { 243ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mActionsGridView = (VerticalGridView) mMainView.findViewById(R.id.guidedactions_list); 244ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (mActionsGridView == null) { 245ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing throw new IllegalStateException("No ListView exists."); 246ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 247ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mActionsGridView.setWindowAlignmentOffset(0); 248ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mActionsGridView.setWindowAlignmentOffsetPercent(50f); 249ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mActionsGridView.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE); 250ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (mSelectorView != null) { 251ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mActionsGridView.setOnScrollListener(new 252ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing SelectorAnimator(mSelectorView, mActionsGridView)); 253ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 254ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 255ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 256ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mActionsGridView.requestFocusFromTouch(); 257ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 258ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (mSelectorView != null) { 259ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // ALlow focus to move to other views 260ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mActionsGridView.getViewTreeObserver().addOnGlobalFocusChangeListener( 261ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing new ViewTreeObserver.OnGlobalFocusChangeListener() { 262ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private boolean mChildFocused; 263ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 264ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 265ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onGlobalFocusChanged(View oldFocus, View newFocus) { 266ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing View focusedChild = mActionsGridView.getFocusedChild(); 267ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (focusedChild == null) { 268ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mSelectorView.setVisibility(View.INVISIBLE); 269ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mChildFocused = false; 270ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } else if (!mChildFocused) { 271ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mChildFocused = true; 272ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mSelectorView.setVisibility(View.VISIBLE); 273ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing updateSelectorView(focusedChild); 274ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 275ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 276ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing }); 277ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 278ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 279ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // Cache widths, chevron alpha values, max and min text lines, etc 280ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing Context ctx = mMainView.getContext(); 281ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing TypedValue val = new TypedValue(); 282ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mEnabledChevronAlpha = getFloat(ctx, val, R.attr.guidedActionEnabledChevronAlpha); 283ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mDisabledChevronAlpha = getFloat(ctx, val, R.attr.guidedActionDisabledChevronAlpha); 284ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mContentWidth = getDimension(ctx, val, R.attr.guidedActionContentWidth); 285ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mContentWidthNoIcon = getDimension(ctx, val, R.attr.guidedActionContentWidthNoIcon); 286ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mTitleMinLines = getInteger(ctx, val, R.attr.guidedActionTitleMinLines); 287ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mTitleMaxLines = getInteger(ctx, val, R.attr.guidedActionTitleMaxLines); 288ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mDescriptionMinLines = getInteger(ctx, val, R.attr.guidedActionDescriptionMinLines); 289ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mVerticalPadding = getDimension(ctx, val, R.attr.guidedActionVerticalPadding); 290ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mDisplayHeight = ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE)) 291ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing .getDefaultDisplay().getHeight(); 292ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 293ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return mMainView; 294ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 295ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 296ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 297ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Returns the VerticalGridView that displays the list of GuidedActions. 298ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @return The VerticalGridView for this presenter. 299ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 300ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public VerticalGridView getActionsGridView() { 301ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return mActionsGridView; 302ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 303ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 304ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 305ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Provides the resource ID of the layout defining the host view for the list of guided actions. 306ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Subclasses may override to provide their own customized layouts. The base implementation 307ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * returns {@link android.support.v17.leanback.R.layout#lb_guidedactions}. If overridden, the 308ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * substituted layout should contain matching IDs for any views that should be managed by the 309ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * base class; this can be achieved by starting with a copy of the base layout file. 310ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @return The resource ID of the layout to be inflated to define the host view for the list 311ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * of GuidedActions. 312ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 313ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public int onProvideLayoutId() { 314ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return R.layout.lb_guidedactions; 315ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 316ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 317ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 318ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Provides the resource ID of the layout defining the view for an individual guided actions. 319ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Subclasses may override to provide their own customized layouts. The base implementation 320ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * returns {@link android.support.v17.leanback.R.layout#lb_guidedactions_item}. If overridden, 321ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * the substituted layout should contain matching IDs for any views that should be managed by 322ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing * the base class; this can be achieved by starting with a copy of the base layout file. Note 323ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing * that in order for the item to support editing, the title view should both subclass {@link 324ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing * android.widget.EditText} and implement {@link ImeKeyMonitor}; see {@link 325ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing * GuidedActionEditText}. 326ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @return The resource ID of the layout to be inflated to define the view to display an 327ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * individual GuidedAction. 328ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 329ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public int onProvideItemLayoutId() { 330ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return R.layout.lb_guidedactions_item; 331ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 332ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 333ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 334ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Constructs a {@link ViewHolder} capable of representing {@link GuidedAction}s. Subclasses 335ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * may choose to return a subclass of ViewHolder. 336ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <p> 337ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <i>Note: Should not actually add the created view to the parent; the caller will do 338ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * this.</i> 339ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param parent The view group to be used as the parent of the new view. 340ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @return The view to be added to the caller's view hierarchy. 341ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 342ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public ViewHolder onCreateViewHolder(ViewGroup parent) { 343ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing LayoutInflater inflater = LayoutInflater.from(parent.getContext()); 344ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing View v = inflater.inflate(onProvideItemLayoutId(), parent, false); 345ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return new ViewHolder(v); 346ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 347ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 348ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 349ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Binds a {@link ViewHolder} to a particular {@link GuidedAction}. 350ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param vh The view holder to be associated with the given action. 351ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param action The guided action to be displayed by the view holder's view. 352ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @return The view to be added to the caller's view hierarchy. 353ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 354ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onBindViewHolder(ViewHolder vh, GuidedAction action) { 355ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 356ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (vh.mTitleView != null) { 357ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mTitleView.setText(action.getTitle()); 358ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 359ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (vh.mDescriptionView != null) { 360ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mDescriptionView.setText(action.getDescription()); 361ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mDescriptionView.setVisibility(TextUtils.isEmpty(action.getDescription()) ? 362ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing View.GONE : View.VISIBLE); 363ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 364ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // Clients might want the check mark view to be gone entirely, in which case, ignore it. 365ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (vh.mCheckmarkView != null && vh.mCheckmarkView.getVisibility() != View.GONE) { 366ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mCheckmarkView.setVisibility(action.isChecked() ? View.VISIBLE : View.INVISIBLE); 367ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 368ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 369ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (vh.mContentView != null) { 370ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing ViewGroup.LayoutParams contentLp = vh.mContentView.getLayoutParams(); 371ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (setIcon(vh.mIconView, action)) { 372ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing contentLp.width = mContentWidth; 373ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } else { 374ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing contentLp.width = mContentWidthNoIcon; 375ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 376ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mContentView.setLayoutParams(contentLp); 377ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 378ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 379ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (vh.mChevronView != null) { 380ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mChevronView.setVisibility(action.hasNext() ? View.VISIBLE : View.INVISIBLE); 381ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mChevronView.setAlpha(action.isEnabled() ? mEnabledChevronAlpha : 382ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mDisabledChevronAlpha); 383ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 384ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 385ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (action.hasMultilineDescription()) { 386ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (vh.mTitleView != null) { 387ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mTitleView.setMaxLines(mTitleMaxLines); 388ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (vh.mDescriptionView != null) { 389ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mDescriptionView.setMaxHeight(getDescriptionMaxHeight(vh.view.getContext(), 390ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mTitleView)); 391ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 392ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 393ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } else { 394ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (vh.mTitleView != null) { 395ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mTitleView.setMaxLines(mTitleMinLines); 396ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 397ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (vh.mDescriptionView != null) { 398ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mDescriptionView.setMaxLines(mDescriptionMinLines); 399ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 400ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 401ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 402ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 403ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 404ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Animates the view holder's view (or subviews thereof) when the action has had its focus 405ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * state changed. 406ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param vh The view holder associated with the relevant action. 407ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param focused True if the action has become focused, false if it has lost focus. 408ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 409ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onAnimateItemFocused(ViewHolder vh, boolean focused) { 410ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // No animations for this, currently, because the animation is done on 411ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // mSelectorView 412ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 413ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 414ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 415ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Animates the view holder's view (or subviews thereof) when the action has had its press 416ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * state changed. 417ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param vh The view holder associated with the relevant action. 418ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param pressed True if the action has been pressed, false if it has been unpressed. 419ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 420ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onAnimateItemPressed(ViewHolder vh, boolean pressed) { 421ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing int attr = pressed ? R.attr.guidedActionPressedAnimation : 422ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing R.attr.guidedActionUnpressedAnimation; 423ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing createAnimator(vh.view, attr).start(); 424ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 425ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 426ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 427ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Animates the view holder's view (or subviews thereof) when the action has had its check 428ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * state changed. 429ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param vh The view holder associated with the relevant action. 430ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param checked True if the action has become checked, false if it has become unchecked. 431ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 432ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onAnimateItemChecked(ViewHolder vh, boolean checked) { 433ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing final View checkView = vh.mCheckmarkView; 434ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (checkView != null) { 435ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (checked) { 436ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing checkView.setVisibility(View.VISIBLE); 437ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing createAnimator(checkView, R.attr.guidedActionCheckedAnimation).start(); 438ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } else { 439633f924bac2b143ae67f86eace4d5068f2acab5eKris Giesing Animator animator = createAnimator(checkView, 440633f924bac2b143ae67f86eace4d5068f2acab5eKris Giesing R.attr.guidedActionUncheckedAnimation); 441ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animator.addListener(new AnimatorListenerAdapter() { 442ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 443ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onAnimationEnd(Animator animation) { 444ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing checkView.setVisibility(View.INVISIBLE); 445ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 446ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing }); 447ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animator.start(); 448ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 449ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 450ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 451ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 452ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /* 453ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * ========================================== 454ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * FragmentAnimationProvider overrides 455ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * ========================================== 456ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 457ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 458ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 459ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * {@inheritDoc} 460ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 461ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 462ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onActivityEnter(@NonNull List<Animator> animators) { 463ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animators.add(createAnimator(mMainView, R.attr.guidedActionsEntryAnimation)); 464ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 465ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 466ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 467ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * {@inheritDoc} 468ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 469ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 470ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onActivityExit(@NonNull List<Animator> animators) {} 471ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 472ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 473ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * {@inheritDoc} 474ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 475ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 476ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onFragmentEnter(@NonNull List<Animator> animators) { 477ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animators.add(createAnimator(mActionsGridView, R.attr.guidedStepEntryAnimation)); 478ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animators.add(createAnimator(mSelectorView, R.attr.guidedStepEntryAnimation)); 479ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 480ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 481ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 482ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * {@inheritDoc} 483ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 484ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 485ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onFragmentExit(@NonNull List<Animator> animators) { 486ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animators.add(createAnimator(mActionsGridView, R.attr.guidedStepExitAnimation)); 487ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animators.add(createAnimator(mSelectorView, R.attr.guidedStepExitAnimation)); 488ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 489ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 490ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 491ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * {@inheritDoc} 492ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 493ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 494ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onFragmentReenter(@NonNull List<Animator> animators) { 495ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animators.add(createAnimator(mActionsGridView, R.attr.guidedStepReentryAnimation)); 496ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animators.add(createAnimator(mSelectorView, R.attr.guidedStepReentryAnimation)); 497ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 498ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 499ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 500ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * {@inheritDoc} 501ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 502ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 503ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onFragmentReturn(@NonNull List<Animator> animators) { 504ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animators.add(createAnimator(mActionsGridView, R.attr.guidedStepReturnAnimation)); 505ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animators.add(createAnimator(mSelectorView, R.attr.guidedStepReturnAnimation)); 506ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 507ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 5084158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing /** 5094158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing * {@inheritDoc} 5104158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing */ 5114158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing @Override 5124158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing public void onImeAppearing(@NonNull List<Animator> animators) { 5134158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing animators.add(createAnimator(mActionsGridView, R.attr.guidedStepImeAppearingAnimation)); 5144158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing animators.add(createAnimator(mSelectorView, R.attr.guidedStepImeAppearingAnimation)); 5154158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing } 5164158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing 5174158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing /** 5184158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing * {@inheritDoc} 5194158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing */ 5204158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing @Override 5214158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing public void onImeDisappearing(@NonNull List<Animator> animators) { 5224158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing animators.add(createAnimator(mActionsGridView, R.attr.guidedStepImeDisappearingAnimation)); 5234158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing animators.add(createAnimator(mSelectorView, R.attr.guidedStepImeDisappearingAnimation)); 5244158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing } 5254158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing 526ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /* 527ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * ========================================== 528ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Private methods 529ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * ========================================== 530ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 531ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 532ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private void updateSelectorView(View focusedChild) { 533ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // Display the selector view. 534ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing int height = focusedChild.getHeight(); 535ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing LayoutParams lp = mSelectorView.getLayoutParams(); 536ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing lp.height = height; 537ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mSelectorView.setLayoutParams(lp); 538ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mSelectorView.setAlpha(1f); 539ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 540ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 541ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private float getFloat(Context ctx, TypedValue typedValue, int attrId) { 542ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing ctx.getTheme().resolveAttribute(attrId, typedValue, true); 543ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // Android resources don't have a native float type, so we have to use strings. 544ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return Float.valueOf(ctx.getResources().getString(typedValue.resourceId)); 545ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 546ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 547ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int getInteger(Context ctx, TypedValue typedValue, int attrId) { 548ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing ctx.getTheme().resolveAttribute(attrId, typedValue, true); 549ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return ctx.getResources().getInteger(typedValue.resourceId); 550ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 551ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 552ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int getDimension(Context ctx, TypedValue typedValue, int attrId) { 553ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing ctx.getTheme().resolveAttribute(attrId, typedValue, true); 554ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return ctx.getResources().getDimensionPixelSize(typedValue.resourceId); 555ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 556ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 557ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private static Animator createAnimator(View v, int attrId) { 558ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing Context ctx = v.getContext(); 559ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing TypedValue typedValue = new TypedValue(); 560ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing ctx.getTheme().resolveAttribute(attrId, typedValue, true); 561ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing Animator animator = AnimatorInflater.loadAnimator(ctx, typedValue.resourceId); 562ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animator.setTarget(v); 563ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return animator; 564ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 565ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 566ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private boolean setIcon(final ImageView iconView, GuidedAction action) { 567ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing Drawable icon = null; 568ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (iconView != null) { 569ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing Context context = iconView.getContext(); 570ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing icon = action.getIcon(); 571ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (icon != null) { 572162b21598d9f4fd49748b3c7e27501fe1277210dChristopher Lane // setImageDrawable resets the drawable's level unless we set the view level first. 573162b21598d9f4fd49748b3c7e27501fe1277210dChristopher Lane iconView.setImageLevel(icon.getLevel()); 574ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing iconView.setImageDrawable(icon); 575ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing iconView.setVisibility(View.VISIBLE); 576ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } else { 577ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing iconView.setVisibility(View.GONE); 578ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 579ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 580ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return icon != null; 581ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 582ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 583ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 584ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @return the max height in pixels the description can be such that the 585ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * action nicely takes up the entire screen. 586ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 587ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int getDescriptionMaxHeight(Context context, TextView title) { 588ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // The 2 multiplier on the title height calculation is a 589ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // conservative estimate for font padding which can not be 590ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // calculated at this stage since the view hasn't been rendered yet. 591ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return (int)(mDisplayHeight - 2*mVerticalPadding - 2*mTitleMaxLines*title.getLineHeight()); 592ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 593ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 594ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 595ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * SelectorAnimator 596ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Controls animation for selected item backgrounds 597ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * TODO: Move into focus animation override? 598ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 599ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private static class SelectorAnimator extends RecyclerView.OnScrollListener { 600ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 601ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private final View mSelectorView; 602ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private final ViewGroup mParentView; 603ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private volatile boolean mFadedOut = true; 604ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 605ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing SelectorAnimator(View selectorView, ViewGroup parentView) { 606ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mSelectorView = selectorView; 607ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mParentView = parentView; 608ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 609ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 610ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // We want to fade in the selector if we've stopped scrolling on it. If 611ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // we're scrolling, we want to ensure to dim the selector if we haven't 612ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // already. We dim the last highlighted view so that while a user is 613ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // scrolling, nothing is highlighted. 614ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 615ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 616ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing Animator animator = null; 617ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing boolean fadingOut = false; 618ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (newState == RecyclerView.SCROLL_STATE_IDLE) { 619ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // The selector starts with a height of 0. In order to scale up from 620ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // 0, we first need the set the height to 1 and scale from there. 621ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing View focusedChild = mParentView.getFocusedChild(); 622ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (focusedChild != null) { 623ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing int selectorHeight = mSelectorView.getHeight(); 624ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing float scaleY = (float) focusedChild.getHeight() / selectorHeight; 625ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing AnimatorSet animators = (AnimatorSet)createAnimator(mSelectorView, 626ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing R.attr.guidedActionsSelectorShowAnimation); 627ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (mFadedOut) { 628ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // selector is completely faded out, so we can just scale before fading in. 629ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mSelectorView.setScaleY(scaleY); 630ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animator = animators.getChildAnimations().get(0); 631ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } else { 632ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // selector is not faded out, so we must animate the scale as we fade in. 633ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing ((ObjectAnimator)animators.getChildAnimations().get(1)) 634ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing .setFloatValues(scaleY); 635ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animator = animators; 636ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 637ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 638ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } else { 639ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animator = createAnimator(mSelectorView, R.attr.guidedActionsSelectorHideAnimation); 640ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing fadingOut = true; 641ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 642ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (animator != null) { 643ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animator.addListener(new Listener(fadingOut)); 644ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animator.start(); 645ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 646ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 647ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 648ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 649ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Sets {@link BaseScrollAdapterFragment#mFadedOut} 650ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * {@link BaseScrollAdapterFragment#mFadedOut} is true, iff 651ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * {@link BaseScrollAdapterFragment#mSelectorView} has an alpha of 0 652ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * (faded out). If false the view either has an alpha of 1 (visible) or 653ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * is in the process of animating. 654ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 655ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private class Listener implements Animator.AnimatorListener { 656ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private boolean mFadingOut; 657ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private boolean mCanceled; 658ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 659ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public Listener(boolean fadingOut) { 660ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mFadingOut = fadingOut; 661ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 662ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 663ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 664ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onAnimationStart(Animator animation) { 665ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (!mFadingOut) { 666ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mFadedOut = false; 667ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 668ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 669ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 670ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 671ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onAnimationEnd(Animator animation) { 672ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (!mCanceled && mFadingOut) { 673ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mFadedOut = true; 674ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 675ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 676ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 677ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 678ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onAnimationCancel(Animator animation) { 679ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mCanceled = true; 680ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 681ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 682ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 683ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onAnimationRepeat(Animator animation) { 684ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 685ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 686ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 687ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 688ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing} 689