147520b68e50572a9775a662410c5aff8300c8784Craig Stout/* 247520b68e50572a9775a662410c5aff8300c8784Craig Stout * Copyright (C) 2014 The Android Open Source Project 347520b68e50572a9775a662410c5aff8300c8784Craig Stout * 447520b68e50572a9775a662410c5aff8300c8784Craig Stout * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 547520b68e50572a9775a662410c5aff8300c8784Craig Stout * in compliance with the License. You may obtain a copy of the License at 647520b68e50572a9775a662410c5aff8300c8784Craig Stout * 747520b68e50572a9775a662410c5aff8300c8784Craig Stout * http://www.apache.org/licenses/LICENSE-2.0 847520b68e50572a9775a662410c5aff8300c8784Craig Stout * 947520b68e50572a9775a662410c5aff8300c8784Craig Stout * Unless required by applicable law or agreed to in writing, software distributed under the License 1047520b68e50572a9775a662410c5aff8300c8784Craig Stout * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 1147520b68e50572a9775a662410c5aff8300c8784Craig Stout * or implied. See the License for the specific language governing permissions and limitations under 1247520b68e50572a9775a662410c5aff8300c8784Craig Stout * the License. 1347520b68e50572a9775a662410c5aff8300c8784Craig Stout */ 14ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.leanback.widget; 1547520b68e50572a9775a662410c5aff8300c8784Craig Stout 16ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; 173103f63e99d47573823957f7aa34308555873221Aurimas Liutikas 184cd4cce277571385f4d1a56d5348578c38368cbeCraig Stoutimport android.graphics.Paint; 1916cb98dc4b7af5eae092a25446a0aa5133f1f5ebDake Guimport android.text.TextUtils; 20268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stoutimport android.view.LayoutInflater; 2147520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.view.View; 2247520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.view.ViewGroup; 234cd4cce277571385f4d1a56d5348578c38368cbeCraig Stoutimport android.widget.TextView; 2447520b68e50572a9775a662410c5aff8300c8784Craig Stout 258619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport androidx.annotation.RestrictTo; 268619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport androidx.leanback.R; 278619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikas 2847520b68e50572a9775a662410c5aff8300c8784Craig Stout/** 29a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * RowHeaderPresenter provides a default presentation for {@link HeaderItem} using a 3033c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu * {@link RowHeaderView} and optionally a TextView for description. If a subclass creates its own 3133c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu * view, the subclass must also override {@link #onCreateViewHolder(ViewGroup)}, 32cb13a318e577e14461eb008071dddf762847de42Dake Gu * {@link #onSelectLevelChanged(ViewHolder)}. 3347520b68e50572a9775a662410c5aff8300c8784Craig Stout */ 3447520b68e50572a9775a662410c5aff8300c8784Craig Stoutpublic class RowHeaderPresenter extends Presenter { 3547520b68e50572a9775a662410c5aff8300c8784Craig Stout 36268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout private final int mLayoutResourceId; 374cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout private final Paint mFontMeasurePaint = new Paint(Paint.ANTI_ALIAS_FLAG); 38ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout private boolean mNullItemVisibilityGone; 398ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu private final boolean mAnimateSelect; 40268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout 4133c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu /** 4233c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu * Creates default RowHeaderPresenter using a title view and a description view. 4333c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu * @see ViewHolder#ViewHolder(View) 4433c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu */ 45268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout public RowHeaderPresenter() { 46268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout this(R.layout.lb_row_header); 47268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout } 48268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout 49268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout /** 50268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout * @hide 51268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout */ 528e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas @RestrictTo(LIBRARY_GROUP) 53268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout public RowHeaderPresenter(int layoutResourceId) { 548ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu this(layoutResourceId, true); 558ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu } 568ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu 578ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu /** 588ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu * @hide 598ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu */ 608e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas @RestrictTo(LIBRARY_GROUP) 618ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu public RowHeaderPresenter(int layoutResourceId, boolean animateSelect) { 62268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout mLayoutResourceId = layoutResourceId; 638ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu mAnimateSelect = animateSelect; 64268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout } 65268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout 66ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout /** 67ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout * Optionally sets the view visibility to {@link View#GONE} when bound to null. 68ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout */ 69ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout public void setNullItemVisibilityGone(boolean nullItemVisibilityGone) { 70ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout mNullItemVisibilityGone = nullItemVisibilityGone; 71ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout } 72ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout 73ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout /** 74ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout * Returns true if the view visibility is set to {@link View#GONE} when bound to null. 75ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout */ 76ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout public boolean isNullItemVisibilityGone() { 77ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout return mNullItemVisibilityGone; 78ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout } 79ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout 80a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout /** 81a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * A ViewHolder for the RowHeaderPresenter. 82a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout */ 8347520b68e50572a9775a662410c5aff8300c8784Craig Stout public static class ViewHolder extends Presenter.ViewHolder { 84cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu float mSelectLevel; 85cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu int mOriginalTextColor; 86268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout float mUnselectAlpha; 8748cbca8d2f412611a09e4f231055f10573a1f45asusnata RowHeaderView mTitleView; 8848cbca8d2f412611a09e4f231055f10573a1f45asusnata TextView mDescriptionView; 89268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout 9033c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu /** 9133c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu * Creating a new ViewHolder that supports title and description. 9233c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu * @param view Root of Views. 9333c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu */ 9447520b68e50572a9775a662410c5aff8300c8784Craig Stout public ViewHolder(View view) { 9547520b68e50572a9775a662410c5aff8300c8784Craig Stout super(view); 9648cbca8d2f412611a09e4f231055f10573a1f45asusnata mTitleView = (RowHeaderView)view.findViewById(R.id.row_header); 9748cbca8d2f412611a09e4f231055f10573a1f45asusnata mDescriptionView = (TextView)view.findViewById(R.id.row_header_description); 9833c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu initColors(); 9933c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu } 10033c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu 10133c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu /** 10233c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu * Uses a single {@link RowHeaderView} for creating a new ViewHolder. 10333c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu * @param view The single RowHeaderView. 10433c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu * @hide 10533c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu */ 10633c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu @RestrictTo(LIBRARY_GROUP) 10733c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu public ViewHolder(RowHeaderView view) { 10833c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu super(view); 10933c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu mTitleView = view; 11033c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu initColors(); 11133c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu } 11233c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu 11333c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu void initColors() { 11433c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu if (mTitleView != null) { 11533c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu mOriginalTextColor = mTitleView.getCurrentTextColor(); 11633c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu } 11733c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu 11833c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu mUnselectAlpha = view.getResources().getFraction( 11933c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu R.fraction.lb_browse_header_unselect_alpha, 1, 1); 12047520b68e50572a9775a662410c5aff8300c8784Craig Stout } 12148cbca8d2f412611a09e4f231055f10573a1f45asusnata 122cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu public final float getSelectLevel() { 123cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu return mSelectLevel; 124cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu } 12547520b68e50572a9775a662410c5aff8300c8784Craig Stout } 12647520b68e50572a9775a662410c5aff8300c8784Craig Stout 12747520b68e50572a9775a662410c5aff8300c8784Craig Stout @Override 12847520b68e50572a9775a662410c5aff8300c8784Craig Stout public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent) { 12948cbca8d2f412611a09e4f231055f10573a1f45asusnata View root = LayoutInflater.from(parent.getContext()) 130268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout .inflate(mLayoutResourceId, parent, false); 131268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout 13248cbca8d2f412611a09e4f231055f10573a1f45asusnata ViewHolder viewHolder = new ViewHolder(root); 1338ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu if (mAnimateSelect) { 1348ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu setSelectLevel(viewHolder, 0); 1358ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu } 136cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu return viewHolder; 13747520b68e50572a9775a662410c5aff8300c8784Craig Stout } 13847520b68e50572a9775a662410c5aff8300c8784Craig Stout 13947520b68e50572a9775a662410c5aff8300c8784Craig Stout @Override 14047520b68e50572a9775a662410c5aff8300c8784Craig Stout public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) { 141ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout HeaderItem headerItem = item == null ? null : ((Row) item).getHeaderItem(); 14248cbca8d2f412611a09e4f231055f10573a1f45asusnata RowHeaderPresenter.ViewHolder vh = (RowHeaderPresenter.ViewHolder)viewHolder; 14350d7840691afde416a8ce3dc8060da1adab687a1susnata if (headerItem == null) { 14433c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu if (vh.mTitleView != null) { 14533c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu vh.mTitleView.setText(null); 14633c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu } 14748cbca8d2f412611a09e4f231055f10573a1f45asusnata if (vh.mDescriptionView != null) { 14848cbca8d2f412611a09e4f231055f10573a1f45asusnata vh.mDescriptionView.setText(null); 14948cbca8d2f412611a09e4f231055f10573a1f45asusnata } 15048cbca8d2f412611a09e4f231055f10573a1f45asusnata 151ac30644710e427c77b9d1f20ae385590bdac6c60Dake Gu viewHolder.view.setContentDescription(null); 152ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout if (mNullItemVisibilityGone) { 153ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout viewHolder.view.setVisibility(View.GONE); 15447520b68e50572a9775a662410c5aff8300c8784Craig Stout } 155ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout } else { 15633c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu if (vh.mTitleView != null) { 15733c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu vh.mTitleView.setText(headerItem.getName()); 15833c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu } 15948cbca8d2f412611a09e4f231055f10573a1f45asusnata if (vh.mDescriptionView != null) { 16016cb98dc4b7af5eae092a25446a0aa5133f1f5ebDake Gu if (TextUtils.isEmpty(headerItem.getDescription())) { 16116cb98dc4b7af5eae092a25446a0aa5133f1f5ebDake Gu vh.mDescriptionView.setVisibility(View.GONE); 16216cb98dc4b7af5eae092a25446a0aa5133f1f5ebDake Gu } else { 16316cb98dc4b7af5eae092a25446a0aa5133f1f5ebDake Gu vh.mDescriptionView.setVisibility(View.VISIBLE); 16416cb98dc4b7af5eae092a25446a0aa5133f1f5ebDake Gu } 16550d7840691afde416a8ce3dc8060da1adab687a1susnata vh.mDescriptionView.setText(headerItem.getDescription()); 16648cbca8d2f412611a09e4f231055f10573a1f45asusnata } 167ac30644710e427c77b9d1f20ae385590bdac6c60Dake Gu viewHolder.view.setContentDescription(headerItem.getContentDescription()); 16850d7840691afde416a8ce3dc8060da1adab687a1susnata viewHolder.view.setVisibility(View.VISIBLE); 16947520b68e50572a9775a662410c5aff8300c8784Craig Stout } 17047520b68e50572a9775a662410c5aff8300c8784Craig Stout } 17147520b68e50572a9775a662410c5aff8300c8784Craig Stout 17247520b68e50572a9775a662410c5aff8300c8784Craig Stout @Override 17347520b68e50572a9775a662410c5aff8300c8784Craig Stout public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) { 17448cbca8d2f412611a09e4f231055f10573a1f45asusnata RowHeaderPresenter.ViewHolder vh = (ViewHolder)viewHolder; 17533c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu if (vh.mTitleView != null) { 17633c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu vh.mTitleView.setText(null); 17733c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu } 17848cbca8d2f412611a09e4f231055f10573a1f45asusnata if (vh.mDescriptionView != null) { 17948cbca8d2f412611a09e4f231055f10573a1f45asusnata vh.mDescriptionView.setText(null); 18048cbca8d2f412611a09e4f231055f10573a1f45asusnata } 18148cbca8d2f412611a09e4f231055f10573a1f45asusnata 1828ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu if (mAnimateSelect) { 1838ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu setSelectLevel((ViewHolder) viewHolder, 0); 1848ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu } 18547520b68e50572a9775a662410c5aff8300c8784Craig Stout } 186cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu 187a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout /** 188a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Sets the select level. 189a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout */ 190cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu public final void setSelectLevel(ViewHolder holder, float selectLevel) { 191cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu holder.mSelectLevel = selectLevel; 192cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu onSelectLevelChanged(holder); 193cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu } 194cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu 195a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout /** 196a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Called when the select level changes. The default implementation sets the alpha on the view. 197a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout */ 198cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu protected void onSelectLevelChanged(ViewHolder holder) { 1998ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu if (mAnimateSelect) { 2003103f63e99d47573823957f7aa34308555873221Aurimas Liutikas holder.view.setAlpha(holder.mUnselectAlpha + holder.mSelectLevel 2013103f63e99d47573823957f7aa34308555873221Aurimas Liutikas * (1f - holder.mUnselectAlpha)); 2028ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu } 203cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu } 2044cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout 2054cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout /** 2064cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout * Returns the space (distance in pixels) below the baseline of the 2074cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout * text view, if one exists; otherwise, returns 0. 2084cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout */ 2094cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout public int getSpaceUnderBaseline(ViewHolder holder) { 2104cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout int space = holder.view.getPaddingBottom(); 2114cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout if (holder.view instanceof TextView) { 2124cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout space += (int) getFontDescent((TextView) holder.view, mFontMeasurePaint); 2134cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout } 2144cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout return space; 2154cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout } 2164cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout 217694edde99dc3782374977dab6d9aa34a16c13337Dake Gu @SuppressWarnings("ReferenceEquality") 2184cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout protected static float getFontDescent(TextView textView, Paint fontMeasurePaint) { 2194cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout if (fontMeasurePaint.getTextSize() != textView.getTextSize()) { 2204cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout fontMeasurePaint.setTextSize(textView.getTextSize()); 2214cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout } 2224cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout if (fontMeasurePaint.getTypeface() != textView.getTypeface()) { 2234cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout fontMeasurePaint.setTypeface(textView.getTypeface()); 2244cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout } 2254cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout return fontMeasurePaint.descent(); 2264cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout } 2274cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout} 228