GuidedActionsStylist.java revision 9562425bf9bc15281ac27df817141854769c1042
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_guidedStepImeAppearingAnimation 914158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepImeDisappearingAnimation 92ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsSelectorShowAnimation 93ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsSelectorHideAnimation 94ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsContainerStyle 95ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsSelectorStyle 96ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsListStyle 97ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemContainerStyle 98ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemCheckmarkStyle 99ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemIconStyle 100ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemContentStyle 101ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemTitleStyle 102ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemDescriptionStyle 103ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemChevronStyle 104ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionCheckedAnimation 105ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionUncheckedAnimation 106ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionPressedAnimation 107ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionUnpressedAnimation 108ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionEnabledChevronAlpha 109ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionDisabledChevronAlpha 110ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionContentWidth 111ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionContentWidthNoIcon 112ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionTitleMinLines 113ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionTitleMaxLines 114ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionDescriptionMinLines 115ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionVerticalPadding 116ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @see android.support.v17.leanback.app.GuidedStepFragment 117ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @see GuidedAction 118ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 119ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingpublic class GuidedActionsStylist implements FragmentAnimationProvider { 120ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 121ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 122ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * ViewHolder caches information about the action item layouts' subviews. Subclasses of {@link 123ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * GuidedActionsStylist} may also wish to subclass this in order to add fields. 124ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @see GuidedAction 125ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 126ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public static class ViewHolder { 127ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 128ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public final View view; 129ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 130ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private View mContentView; 131ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private TextView mTitleView; 132ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private TextView mDescriptionView; 133ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private ImageView mIconView; 134ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private ImageView mCheckmarkView; 135ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private ImageView mChevronView; 136c1741246af607f6be2389056da0182c40f938348Dake Gu private boolean mInEditing; 137c1741246af607f6be2389056da0182c40f938348Dake Gu private boolean mInEditingDescription; 138ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 139ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 140ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Constructs an ViewHolder and caches the relevant subviews. 141ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 142ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public ViewHolder(View v) { 143ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing view = v; 144ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 145ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mContentView = v.findViewById(R.id.guidedactions_item_content); 146ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mTitleView = (TextView) v.findViewById(R.id.guidedactions_item_title); 147ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mDescriptionView = (TextView) v.findViewById(R.id.guidedactions_item_description); 148ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mIconView = (ImageView) v.findViewById(R.id.guidedactions_item_icon); 149ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mCheckmarkView = (ImageView) v.findViewById(R.id.guidedactions_item_checkmark); 150ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mChevronView = (ImageView) v.findViewById(R.id.guidedactions_item_chevron); 151ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 152ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 153ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 154ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Returns the content view within this view holder's view, where title and description are 155ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * shown. 156ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 157ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public View getContentView() { 158ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return mContentView; 159ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 160ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 161ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 162ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Returns the title view within this view holder's view. 163ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 164ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public TextView getTitleView() { 165ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return mTitleView; 166ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 167ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 168ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 169ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing * Convenience method to return an editable version of the title, if possible, 170ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing * or null if the title view isn't an EditText. 171ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing */ 172ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing public EditText getEditableTitleView() { 173ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing return (mTitleView instanceof EditText) ? (EditText)mTitleView : null; 174ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing } 175ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing 176ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing /** 177ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Returns the description view within this view holder's view. 178ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 179ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public TextView getDescriptionView() { 180ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return mDescriptionView; 181ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 182ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 183ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 184c1741246af607f6be2389056da0182c40f938348Dake Gu * Convenience method to return an editable version of the description, if possible, 185c1741246af607f6be2389056da0182c40f938348Dake Gu * or null if the description view isn't an EditText. 186c1741246af607f6be2389056da0182c40f938348Dake Gu */ 187c1741246af607f6be2389056da0182c40f938348Dake Gu public EditText getEditableDescriptionView() { 188c1741246af607f6be2389056da0182c40f938348Dake Gu return (mDescriptionView instanceof EditText) ? (EditText)mDescriptionView : null; 189c1741246af607f6be2389056da0182c40f938348Dake Gu } 190c1741246af607f6be2389056da0182c40f938348Dake Gu 191c1741246af607f6be2389056da0182c40f938348Dake Gu /** 192ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Returns the icon view within this view holder's view. 193ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 194ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public ImageView getIconView() { 195ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return mIconView; 196ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 197ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 198ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 199ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Returns the checkmark view within this view holder's view. 200ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 201ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public ImageView getCheckmarkView() { 202ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return mCheckmarkView; 203ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 204ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 205ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 206ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Returns the chevron view within this view holder's view. 207ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 208ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public ImageView getChevronView() { 209ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return mChevronView; 210ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 211ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 212c1741246af607f6be2389056da0182c40f938348Dake Gu /** 213c1741246af607f6be2389056da0182c40f938348Dake Gu * Returns true if the TextView is in editing title or description, false otherwise. 214c1741246af607f6be2389056da0182c40f938348Dake Gu */ 215c1741246af607f6be2389056da0182c40f938348Dake Gu public boolean isInEditing() { 216c1741246af607f6be2389056da0182c40f938348Dake Gu return mInEditing; 217c1741246af607f6be2389056da0182c40f938348Dake Gu } 218c1741246af607f6be2389056da0182c40f938348Dake Gu 219c1741246af607f6be2389056da0182c40f938348Dake Gu /** 220c1741246af607f6be2389056da0182c40f938348Dake Gu * Returns true if the TextView is in editing description, false otherwise. 221c1741246af607f6be2389056da0182c40f938348Dake Gu */ 222c1741246af607f6be2389056da0182c40f938348Dake Gu public boolean isInEditingDescription() { 223c1741246af607f6be2389056da0182c40f938348Dake Gu return mInEditingDescription; 224c1741246af607f6be2389056da0182c40f938348Dake Gu } 225c1741246af607f6be2389056da0182c40f938348Dake Gu 226c1741246af607f6be2389056da0182c40f938348Dake Gu public View getEditingView() { 227c1741246af607f6be2389056da0182c40f938348Dake Gu if (mInEditing) { 228c1741246af607f6be2389056da0182c40f938348Dake Gu return mInEditingDescription ? mDescriptionView : mTitleView; 229c1741246af607f6be2389056da0182c40f938348Dake Gu } else { 230c1741246af607f6be2389056da0182c40f938348Dake Gu return null; 231c1741246af607f6be2389056da0182c40f938348Dake Gu } 232c1741246af607f6be2389056da0182c40f938348Dake Gu } 233ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 234ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 235ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private static String TAG = "GuidedActionsStylist"; 236ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 237ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing protected View mMainView; 238ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing protected VerticalGridView mActionsGridView; 239ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing protected View mSelectorView; 240ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 241ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // Cached values from resources 242c1741246af607f6be2389056da0182c40f938348Dake Gu private float mEnabledTextAlpha; 243c1741246af607f6be2389056da0182c40f938348Dake Gu private float mDisabledTextAlpha; 244c1741246af607f6be2389056da0182c40f938348Dake Gu private float mEnabledDescriptionAlpha; 245c1741246af607f6be2389056da0182c40f938348Dake Gu private float mDisabledDescriptionAlpha; 246ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private float mEnabledChevronAlpha; 247ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private float mDisabledChevronAlpha; 248ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int mContentWidth; 249ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int mContentWidthNoIcon; 250ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int mTitleMinLines; 251ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int mTitleMaxLines; 252ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int mDescriptionMinLines; 253ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int mVerticalPadding; 254ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int mDisplayHeight; 255ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 256ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 257ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Creates a view appropriate for displaying a list of GuidedActions, using the provided 258ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * inflater and container. 259ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <p> 260ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <i>Note: Does not actually add the created view to the container; the caller should do 261ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * this.</i> 262ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param inflater The layout inflater to be used when constructing the view. 263ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param container The view group to be passed in the call to 264ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <code>LayoutInflater.inflate</code>. 265ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @return The view to be added to the caller's view hierarchy. 266ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 267ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public View onCreateView(LayoutInflater inflater, ViewGroup container) { 268ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mMainView = inflater.inflate(onProvideLayoutId(), container, false); 269ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mSelectorView = mMainView.findViewById(R.id.guidedactions_selector); 270ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (mMainView instanceof VerticalGridView) { 271ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mActionsGridView = (VerticalGridView) mMainView; 272ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } else { 273ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mActionsGridView = (VerticalGridView) mMainView.findViewById(R.id.guidedactions_list); 274ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (mActionsGridView == null) { 275ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing throw new IllegalStateException("No ListView exists."); 276ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 277ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mActionsGridView.setWindowAlignmentOffset(0); 278ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mActionsGridView.setWindowAlignmentOffsetPercent(50f); 279ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mActionsGridView.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE); 280ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (mSelectorView != null) { 281ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mActionsGridView.setOnScrollListener(new 282ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing SelectorAnimator(mSelectorView, mActionsGridView)); 283ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 284ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 285ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 286ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mActionsGridView.requestFocusFromTouch(); 287ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 288ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (mSelectorView != null) { 289ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // ALlow focus to move to other views 290ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mActionsGridView.getViewTreeObserver().addOnGlobalFocusChangeListener( 291ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing new ViewTreeObserver.OnGlobalFocusChangeListener() { 292ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private boolean mChildFocused; 293ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 294ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 295ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onGlobalFocusChanged(View oldFocus, View newFocus) { 296ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing View focusedChild = mActionsGridView.getFocusedChild(); 297ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (focusedChild == null) { 298ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mSelectorView.setVisibility(View.INVISIBLE); 299ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mChildFocused = false; 300ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } else if (!mChildFocused) { 301ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mChildFocused = true; 302ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mSelectorView.setVisibility(View.VISIBLE); 303ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing updateSelectorView(focusedChild); 304ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 305ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 306ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing }); 307ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 308ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 309ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // Cache widths, chevron alpha values, max and min text lines, etc 310ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing Context ctx = mMainView.getContext(); 311ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing TypedValue val = new TypedValue(); 312ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mEnabledChevronAlpha = getFloat(ctx, val, R.attr.guidedActionEnabledChevronAlpha); 313ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mDisabledChevronAlpha = getFloat(ctx, val, R.attr.guidedActionDisabledChevronAlpha); 314ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mContentWidth = getDimension(ctx, val, R.attr.guidedActionContentWidth); 315ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mContentWidthNoIcon = getDimension(ctx, val, R.attr.guidedActionContentWidthNoIcon); 316ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mTitleMinLines = getInteger(ctx, val, R.attr.guidedActionTitleMinLines); 317ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mTitleMaxLines = getInteger(ctx, val, R.attr.guidedActionTitleMaxLines); 318ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mDescriptionMinLines = getInteger(ctx, val, R.attr.guidedActionDescriptionMinLines); 319ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mVerticalPadding = getDimension(ctx, val, R.attr.guidedActionVerticalPadding); 320ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mDisplayHeight = ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE)) 321ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing .getDefaultDisplay().getHeight(); 322ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 323c1741246af607f6be2389056da0182c40f938348Dake Gu mEnabledTextAlpha = Float.valueOf(ctx.getResources().getString(R.string 324c1741246af607f6be2389056da0182c40f938348Dake Gu .lb_guidedactions_item_unselected_text_alpha)); 325c1741246af607f6be2389056da0182c40f938348Dake Gu mDisabledTextAlpha = Float.valueOf(ctx.getResources().getString(R.string 326c1741246af607f6be2389056da0182c40f938348Dake Gu .lb_guidedactions_item_disabled_text_alpha)); 327c1741246af607f6be2389056da0182c40f938348Dake Gu mEnabledDescriptionAlpha = Float.valueOf(ctx.getResources().getString(R.string 328c1741246af607f6be2389056da0182c40f938348Dake Gu .lb_guidedactions_item_unselected_description_text_alpha)); 329c1741246af607f6be2389056da0182c40f938348Dake Gu mDisabledDescriptionAlpha = Float.valueOf(ctx.getResources().getString(R.string 330c1741246af607f6be2389056da0182c40f938348Dake Gu .lb_guidedactions_item_disabled_description_text_alpha)); 331ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return mMainView; 332ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 333ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 334ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 335ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Returns the VerticalGridView that displays the list of GuidedActions. 336ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @return The VerticalGridView for this presenter. 337ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 338ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public VerticalGridView getActionsGridView() { 339ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return mActionsGridView; 340ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 341ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 342ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 343ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Provides the resource ID of the layout defining the host view for the list of guided actions. 344ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Subclasses may override to provide their own customized layouts. The base implementation 345ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * returns {@link android.support.v17.leanback.R.layout#lb_guidedactions}. If overridden, the 346ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * substituted layout should contain matching IDs for any views that should be managed by the 347ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * base class; this can be achieved by starting with a copy of the base layout file. 348ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @return The resource ID of the layout to be inflated to define the host view for the list 349ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * of GuidedActions. 350ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 351ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public int onProvideLayoutId() { 352ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return R.layout.lb_guidedactions; 353ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 354ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 355ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 356ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Provides the resource ID of the layout defining the view for an individual guided actions. 357ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Subclasses may override to provide their own customized layouts. The base implementation 358ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * returns {@link android.support.v17.leanback.R.layout#lb_guidedactions_item}. If overridden, 359ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * the substituted layout should contain matching IDs for any views that should be managed by 360ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing * the base class; this can be achieved by starting with a copy of the base layout file. Note 361ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing * that in order for the item to support editing, the title view should both subclass {@link 362ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing * android.widget.EditText} and implement {@link ImeKeyMonitor}; see {@link 363ac07e9d12b10138d4a449522f7082a40f18861e2Kris Giesing * GuidedActionEditText}. 364ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @return The resource ID of the layout to be inflated to define the view to display an 365ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * individual GuidedAction. 366ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 367ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public int onProvideItemLayoutId() { 368ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return R.layout.lb_guidedactions_item; 369ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 370ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 371ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 372ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Constructs a {@link ViewHolder} capable of representing {@link GuidedAction}s. Subclasses 373ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * may choose to return a subclass of ViewHolder. 374ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <p> 375ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <i>Note: Should not actually add the created view to the parent; the caller will do 376ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * this.</i> 377ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param parent The view group to be used as the parent of the new view. 378ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @return The view to be added to the caller's view hierarchy. 379ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 380ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public ViewHolder onCreateViewHolder(ViewGroup parent) { 381ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing LayoutInflater inflater = LayoutInflater.from(parent.getContext()); 382ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing View v = inflater.inflate(onProvideItemLayoutId(), parent, false); 383ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return new ViewHolder(v); 384ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 385ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 386ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 387ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Binds a {@link ViewHolder} to a particular {@link GuidedAction}. 388ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param vh The view holder to be associated with the given action. 389ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param action The guided action to be displayed by the view holder's view. 390ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @return The view to be added to the caller's view hierarchy. 391ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 392ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onBindViewHolder(ViewHolder vh, GuidedAction action) { 393ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 394ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (vh.mTitleView != null) { 395ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mTitleView.setText(action.getTitle()); 396c1741246af607f6be2389056da0182c40f938348Dake Gu vh.mTitleView.setAlpha(action.isEnabled() ? mEnabledTextAlpha : mDisabledTextAlpha); 397ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 398ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (vh.mDescriptionView != null) { 399ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mDescriptionView.setText(action.getDescription()); 400ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mDescriptionView.setVisibility(TextUtils.isEmpty(action.getDescription()) ? 401ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing View.GONE : View.VISIBLE); 402c1741246af607f6be2389056da0182c40f938348Dake Gu vh.mDescriptionView.setAlpha(action.isEnabled() ? mEnabledDescriptionAlpha : 403c1741246af607f6be2389056da0182c40f938348Dake Gu mDisabledDescriptionAlpha); 404ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 405ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // Clients might want the check mark view to be gone entirely, in which case, ignore it. 406ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (vh.mCheckmarkView != null && vh.mCheckmarkView.getVisibility() != View.GONE) { 407ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mCheckmarkView.setVisibility(action.isChecked() ? View.VISIBLE : View.INVISIBLE); 408ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 409ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 410ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (vh.mContentView != null) { 411ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing ViewGroup.LayoutParams contentLp = vh.mContentView.getLayoutParams(); 412ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (setIcon(vh.mIconView, action)) { 413ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing contentLp.width = mContentWidth; 414ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } else { 415ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing contentLp.width = mContentWidthNoIcon; 416ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 417ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mContentView.setLayoutParams(contentLp); 418ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 419ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 420ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (vh.mChevronView != null) { 421ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mChevronView.setVisibility(action.hasNext() ? View.VISIBLE : View.INVISIBLE); 422ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mChevronView.setAlpha(action.isEnabled() ? mEnabledChevronAlpha : 423ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mDisabledChevronAlpha); 424ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 425ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 426ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (action.hasMultilineDescription()) { 427ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (vh.mTitleView != null) { 428ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mTitleView.setMaxLines(mTitleMaxLines); 429ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (vh.mDescriptionView != null) { 430ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mDescriptionView.setMaxHeight(getDescriptionMaxHeight(vh.view.getContext(), 431ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mTitleView)); 432ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 433ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 434ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } else { 435ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (vh.mTitleView != null) { 436ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mTitleView.setMaxLines(mTitleMinLines); 437ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 438ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (vh.mDescriptionView != null) { 439ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing vh.mDescriptionView.setMaxLines(mDescriptionMinLines); 440ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 441ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 442c1741246af607f6be2389056da0182c40f938348Dake Gu setEditingMode(vh, action, false); 443c1741246af607f6be2389056da0182c40f938348Dake Gu } 444c1741246af607f6be2389056da0182c40f938348Dake Gu 445c1741246af607f6be2389056da0182c40f938348Dake Gu public void setEditingMode(ViewHolder vh, GuidedAction action, boolean editing) { 446c1741246af607f6be2389056da0182c40f938348Dake Gu if (editing != vh.mInEditing) { 447c1741246af607f6be2389056da0182c40f938348Dake Gu vh.mInEditing = editing; 448c1741246af607f6be2389056da0182c40f938348Dake Gu onEditingModeChange(vh, action, editing); 449c1741246af607f6be2389056da0182c40f938348Dake Gu } 450c1741246af607f6be2389056da0182c40f938348Dake Gu } 451c1741246af607f6be2389056da0182c40f938348Dake Gu 452c1741246af607f6be2389056da0182c40f938348Dake Gu protected void onEditingModeChange(ViewHolder vh, GuidedAction action, boolean editing) { 453c1741246af607f6be2389056da0182c40f938348Dake Gu TextView titleView = vh.getTitleView(); 454c1741246af607f6be2389056da0182c40f938348Dake Gu TextView descriptionView = vh.getDescriptionView(); 455c1741246af607f6be2389056da0182c40f938348Dake Gu if (editing) { 456c1741246af607f6be2389056da0182c40f938348Dake Gu CharSequence editTitle = action.getEditTitle(); 457c1741246af607f6be2389056da0182c40f938348Dake Gu if (titleView != null && editTitle != null) { 458c1741246af607f6be2389056da0182c40f938348Dake Gu titleView.setText(editTitle); 459c1741246af607f6be2389056da0182c40f938348Dake Gu } 460c1741246af607f6be2389056da0182c40f938348Dake Gu CharSequence editDescription = action.getEditDescription(); 461c1741246af607f6be2389056da0182c40f938348Dake Gu if (descriptionView != null && editDescription != null) { 462c1741246af607f6be2389056da0182c40f938348Dake Gu descriptionView.setText(editDescription); 463c1741246af607f6be2389056da0182c40f938348Dake Gu } 464c1741246af607f6be2389056da0182c40f938348Dake Gu if (action.isDescriptionEditable()) { 465c1741246af607f6be2389056da0182c40f938348Dake Gu if (descriptionView != null) { 466c1741246af607f6be2389056da0182c40f938348Dake Gu descriptionView.setVisibility(View.VISIBLE); 4679562425bf9bc15281ac27df817141854769c1042Dake Gu descriptionView.setInputType(action.getDescriptionEditInputType()); 468c1741246af607f6be2389056da0182c40f938348Dake Gu } 469c1741246af607f6be2389056da0182c40f938348Dake Gu vh.mInEditingDescription = true; 470c1741246af607f6be2389056da0182c40f938348Dake Gu } else { 471c1741246af607f6be2389056da0182c40f938348Dake Gu vh.mInEditingDescription = false; 4729562425bf9bc15281ac27df817141854769c1042Dake Gu if (titleView != null) { 4739562425bf9bc15281ac27df817141854769c1042Dake Gu titleView.setInputType(action.getEditInputType()); 4749562425bf9bc15281ac27df817141854769c1042Dake Gu } 475c1741246af607f6be2389056da0182c40f938348Dake Gu } 476c1741246af607f6be2389056da0182c40f938348Dake Gu } else { 477c1741246af607f6be2389056da0182c40f938348Dake Gu if (titleView != null) { 478c1741246af607f6be2389056da0182c40f938348Dake Gu titleView.setText(action.getTitle()); 479c1741246af607f6be2389056da0182c40f938348Dake Gu } 480c1741246af607f6be2389056da0182c40f938348Dake Gu if (descriptionView != null) { 481c1741246af607f6be2389056da0182c40f938348Dake Gu descriptionView.setText(action.getDescription()); 482c1741246af607f6be2389056da0182c40f938348Dake Gu } 483c1741246af607f6be2389056da0182c40f938348Dake Gu if (vh.mInEditingDescription) { 484c1741246af607f6be2389056da0182c40f938348Dake Gu if (descriptionView != null) { 485c1741246af607f6be2389056da0182c40f938348Dake Gu descriptionView.setVisibility(TextUtils.isEmpty(action.getDescription()) ? 486c1741246af607f6be2389056da0182c40f938348Dake Gu View.GONE : View.VISIBLE); 4879562425bf9bc15281ac27df817141854769c1042Dake Gu descriptionView.setInputType(action.getDescriptionInputType()); 488c1741246af607f6be2389056da0182c40f938348Dake Gu } 489c1741246af607f6be2389056da0182c40f938348Dake Gu vh.mInEditingDescription = false; 4909562425bf9bc15281ac27df817141854769c1042Dake Gu } else { 4919562425bf9bc15281ac27df817141854769c1042Dake Gu if (titleView != null) { 4929562425bf9bc15281ac27df817141854769c1042Dake Gu titleView.setInputType(action.getInputType()); 4939562425bf9bc15281ac27df817141854769c1042Dake Gu } 494c1741246af607f6be2389056da0182c40f938348Dake Gu } 495c1741246af607f6be2389056da0182c40f938348Dake Gu } 496ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 497ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 498ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 499ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Animates the view holder's view (or subviews thereof) when the action has had its focus 500ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * state changed. 501ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param vh The view holder associated with the relevant action. 502ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param focused True if the action has become focused, false if it has lost focus. 503ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 504ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onAnimateItemFocused(ViewHolder vh, boolean focused) { 505ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // No animations for this, currently, because the animation is done on 506ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // mSelectorView 507ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 508ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 509ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 510ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Animates the view holder's view (or subviews thereof) when the action has had its press 511ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * state changed. 512ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param vh The view holder associated with the relevant action. 513ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param pressed True if the action has been pressed, false if it has been unpressed. 514ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 515ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onAnimateItemPressed(ViewHolder vh, boolean pressed) { 516ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing int attr = pressed ? R.attr.guidedActionPressedAnimation : 517ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing R.attr.guidedActionUnpressedAnimation; 518ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing createAnimator(vh.view, attr).start(); 519ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 520ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 521ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 522ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Animates the view holder's view (or subviews thereof) when the action has had its check 523ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * state changed. 524ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param vh The view holder associated with the relevant action. 525ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @param checked True if the action has become checked, false if it has become unchecked. 526ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 527ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onAnimateItemChecked(ViewHolder vh, boolean checked) { 528ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing final View checkView = vh.mCheckmarkView; 529ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (checkView != null) { 530ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (checked) { 531ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing checkView.setVisibility(View.VISIBLE); 532ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing createAnimator(checkView, R.attr.guidedActionCheckedAnimation).start(); 533ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } else { 534633f924bac2b143ae67f86eace4d5068f2acab5eKris Giesing Animator animator = createAnimator(checkView, 535633f924bac2b143ae67f86eace4d5068f2acab5eKris Giesing R.attr.guidedActionUncheckedAnimation); 536ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animator.addListener(new AnimatorListenerAdapter() { 537ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 538ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onAnimationEnd(Animator animation) { 539ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing checkView.setVisibility(View.INVISIBLE); 540ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 541ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing }); 542ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animator.start(); 543ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 544ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 545ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 546ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 547ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /* 548ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * ========================================== 549ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * FragmentAnimationProvider overrides 550ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * ========================================== 551ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 552ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 553ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 554ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * {@inheritDoc} 555ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 556ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 5574158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing public void onImeAppearing(@NonNull List<Animator> animators) { 5584158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing animators.add(createAnimator(mActionsGridView, R.attr.guidedStepImeAppearingAnimation)); 5594158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing animators.add(createAnimator(mSelectorView, R.attr.guidedStepImeAppearingAnimation)); 5604158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing } 5614158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing 5624158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing /** 5634158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing * {@inheritDoc} 5644158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing */ 5654158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing @Override 5664158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing public void onImeDisappearing(@NonNull List<Animator> animators) { 5674158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing animators.add(createAnimator(mActionsGridView, R.attr.guidedStepImeDisappearingAnimation)); 5684158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing animators.add(createAnimator(mSelectorView, R.attr.guidedStepImeDisappearingAnimation)); 5694158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing } 5704158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing 571ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /* 572ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * ========================================== 573ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Private methods 574ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * ========================================== 575ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 576ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 577ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private void updateSelectorView(View focusedChild) { 578ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // Display the selector view. 579ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing int height = focusedChild.getHeight(); 580ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing LayoutParams lp = mSelectorView.getLayoutParams(); 581ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing lp.height = height; 582ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mSelectorView.setLayoutParams(lp); 583ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mSelectorView.setAlpha(1f); 584ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 585ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 586ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private float getFloat(Context ctx, TypedValue typedValue, int attrId) { 587ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing ctx.getTheme().resolveAttribute(attrId, typedValue, true); 588ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // Android resources don't have a native float type, so we have to use strings. 589ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return Float.valueOf(ctx.getResources().getString(typedValue.resourceId)); 590ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 591ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 592ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int getInteger(Context ctx, TypedValue typedValue, int attrId) { 593ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing ctx.getTheme().resolveAttribute(attrId, typedValue, true); 594ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return ctx.getResources().getInteger(typedValue.resourceId); 595ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 596ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 597ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int getDimension(Context ctx, TypedValue typedValue, int attrId) { 598ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing ctx.getTheme().resolveAttribute(attrId, typedValue, true); 599ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return ctx.getResources().getDimensionPixelSize(typedValue.resourceId); 600ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 601ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 602ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private static Animator createAnimator(View v, int attrId) { 603ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing Context ctx = v.getContext(); 604ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing TypedValue typedValue = new TypedValue(); 605ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing ctx.getTheme().resolveAttribute(attrId, typedValue, true); 606ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing Animator animator = AnimatorInflater.loadAnimator(ctx, typedValue.resourceId); 607ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animator.setTarget(v); 608ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return animator; 609ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 610ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 611ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private boolean setIcon(final ImageView iconView, GuidedAction action) { 612ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing Drawable icon = null; 613ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (iconView != null) { 614ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing Context context = iconView.getContext(); 615ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing icon = action.getIcon(); 616ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (icon != null) { 617162b21598d9f4fd49748b3c7e27501fe1277210dChristopher Lane // setImageDrawable resets the drawable's level unless we set the view level first. 618162b21598d9f4fd49748b3c7e27501fe1277210dChristopher Lane iconView.setImageLevel(icon.getLevel()); 619ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing iconView.setImageDrawable(icon); 620ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing iconView.setVisibility(View.VISIBLE); 621ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } else { 622ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing iconView.setVisibility(View.GONE); 623ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 624ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 625ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return icon != null; 626ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 627ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 628ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 629ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @return the max height in pixels the description can be such that the 630ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * action nicely takes up the entire screen. 631ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 632ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private int getDescriptionMaxHeight(Context context, TextView title) { 633ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // The 2 multiplier on the title height calculation is a 634ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // conservative estimate for font padding which can not be 635ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // calculated at this stage since the view hasn't been rendered yet. 636ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing return (int)(mDisplayHeight - 2*mVerticalPadding - 2*mTitleMaxLines*title.getLineHeight()); 637ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 638ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 639ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 640ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * SelectorAnimator 641ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Controls animation for selected item backgrounds 642ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * TODO: Move into focus animation override? 643ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 644ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private static class SelectorAnimator extends RecyclerView.OnScrollListener { 645ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 646ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private final View mSelectorView; 647ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private final ViewGroup mParentView; 648ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private volatile boolean mFadedOut = true; 649ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 650ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing SelectorAnimator(View selectorView, ViewGroup parentView) { 651ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mSelectorView = selectorView; 652ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mParentView = parentView; 653ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 654ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 655ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // We want to fade in the selector if we've stopped scrolling on it. If 656ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // we're scrolling, we want to ensure to dim the selector if we haven't 657ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // already. We dim the last highlighted view so that while a user is 658ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // scrolling, nothing is highlighted. 659ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 660ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 661ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing Animator animator = null; 662ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing boolean fadingOut = false; 663ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (newState == RecyclerView.SCROLL_STATE_IDLE) { 664ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // The selector starts with a height of 0. In order to scale up from 665ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // 0, we first need the set the height to 1 and scale from there. 666ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing View focusedChild = mParentView.getFocusedChild(); 667ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (focusedChild != null) { 668ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing int selectorHeight = mSelectorView.getHeight(); 669ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing float scaleY = (float) focusedChild.getHeight() / selectorHeight; 670ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing AnimatorSet animators = (AnimatorSet)createAnimator(mSelectorView, 671ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing R.attr.guidedActionsSelectorShowAnimation); 672ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (mFadedOut) { 673ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // selector is completely faded out, so we can just scale before fading in. 674ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mSelectorView.setScaleY(scaleY); 675ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animator = animators.getChildAnimations().get(0); 676ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } else { 677ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing // selector is not faded out, so we must animate the scale as we fade in. 678ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing ((ObjectAnimator)animators.getChildAnimations().get(1)) 679ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing .setFloatValues(scaleY); 680ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animator = animators; 681ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 682ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 683ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } else { 684ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animator = createAnimator(mSelectorView, R.attr.guidedActionsSelectorHideAnimation); 685ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing fadingOut = true; 686ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 687ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (animator != null) { 688ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animator.addListener(new Listener(fadingOut)); 689ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing animator.start(); 690ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 691ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 692ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 693ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing /** 694ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Sets {@link BaseScrollAdapterFragment#mFadedOut} 695ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * {@link BaseScrollAdapterFragment#mFadedOut} is true, iff 696ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * {@link BaseScrollAdapterFragment#mSelectorView} has an alpha of 0 697ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * (faded out). If false the view either has an alpha of 1 (visible) or 698ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * is in the process of animating. 699ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */ 700ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private class Listener implements Animator.AnimatorListener { 701ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private boolean mFadingOut; 702ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing private boolean mCanceled; 703ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 704ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public Listener(boolean fadingOut) { 705ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mFadingOut = fadingOut; 706ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 707ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 708ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 709ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onAnimationStart(Animator animation) { 710ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (!mFadingOut) { 711ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mFadedOut = false; 712ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 713ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 714ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 715ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 716ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onAnimationEnd(Animator animation) { 717ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing if (!mCanceled && mFadingOut) { 718ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mFadedOut = true; 719ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 720ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 721ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 722ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 723ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onAnimationCancel(Animator animation) { 724ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing mCanceled = true; 725ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 726ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 727ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing @Override 728ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing public void onAnimationRepeat(Animator animation) { 729ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 730ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 731ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing } 732ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing 733ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing} 734