1 // CHECKSTYLE:OFF Generated code 2 /* This file is auto-generated from HeadersSupportFragment.java. DO NOT MODIFY. */ 3 4 /* 5 * Copyright (C) 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 8 * in compliance with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software distributed under the License 13 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 14 * or implied. See the License for the specific language governing permissions and limitations under 15 * the License. 16 */ 17 18 package android.support.v17.leanback.app; 19 20 import android.content.Context; 21 import android.graphics.Color; 22 import android.graphics.drawable.ColorDrawable; 23 import android.graphics.drawable.Drawable; 24 import android.graphics.drawable.GradientDrawable; 25 import android.os.Bundle; 26 import android.support.v17.leanback.R; 27 import android.support.v17.leanback.widget.ClassPresenterSelector; 28 import android.support.v17.leanback.widget.DividerPresenter; 29 import android.support.v17.leanback.widget.DividerRow; 30 import android.support.v17.leanback.widget.FocusHighlightHelper; 31 import android.support.v17.leanback.widget.HorizontalGridView; 32 import android.support.v17.leanback.widget.ItemBridgeAdapter; 33 import android.support.v17.leanback.widget.PresenterSelector; 34 import android.support.v17.leanback.widget.Row; 35 import android.support.v17.leanback.widget.RowHeaderPresenter; 36 import android.support.v17.leanback.widget.SectionRow; 37 import android.support.v17.leanback.widget.VerticalGridView; 38 import android.support.v7.widget.RecyclerView; 39 import android.view.View; 40 import android.view.View.OnLayoutChangeListener; 41 import android.view.ViewGroup; 42 import android.widget.FrameLayout; 43 44 /** 45 * An fragment containing a list of row headers. Implementation must support three types of rows: 46 * <ul> 47 * <li>{@link DividerRow} rendered by {@link DividerPresenter}.</li> 48 * <li>{@link Row} rendered by {@link RowHeaderPresenter}.</li> 49 * <li>{@link SectionRow} rendered by {@link RowHeaderPresenter}.</li> 50 * </ul> 51 * Use {@link #setPresenterSelector(PresenterSelector)} in subclass constructor to customize 52 * Presenters. App may override {@link BrowseFragment#onCreateHeadersFragment()}. 53 */ 54 public class HeadersFragment extends BaseRowFragment { 55 56 /** 57 * Interface definition for a callback to be invoked when a header item is clicked. 58 */ 59 public interface OnHeaderClickedListener { 60 /** 61 * Called when a header item has been clicked. 62 * 63 * @param viewHolder Row ViewHolder object corresponding to the selected Header. 64 * @param row Row object corresponding to the selected Header. 65 */ onHeaderClicked(RowHeaderPresenter.ViewHolder viewHolder, Row row)66 void onHeaderClicked(RowHeaderPresenter.ViewHolder viewHolder, Row row); 67 } 68 69 /** 70 * Interface definition for a callback to be invoked when a header item is selected. 71 */ 72 public interface OnHeaderViewSelectedListener { 73 /** 74 * Called when a header item has been selected. 75 * 76 * @param viewHolder Row ViewHolder object corresponding to the selected Header. 77 * @param row Row object corresponding to the selected Header. 78 */ onHeaderSelected(RowHeaderPresenter.ViewHolder viewHolder, Row row)79 void onHeaderSelected(RowHeaderPresenter.ViewHolder viewHolder, Row row); 80 } 81 82 private OnHeaderViewSelectedListener mOnHeaderViewSelectedListener; 83 OnHeaderClickedListener mOnHeaderClickedListener; 84 private boolean mHeadersEnabled = true; 85 private boolean mHeadersGone = false; 86 private int mBackgroundColor; 87 private boolean mBackgroundColorSet; 88 89 private static final PresenterSelector sHeaderPresenter = new ClassPresenterSelector() 90 .addClassPresenter(DividerRow.class, new DividerPresenter()) 91 .addClassPresenter(SectionRow.class, 92 new RowHeaderPresenter(R.layout.lb_section_header, false)) 93 .addClassPresenter(Row.class, new RowHeaderPresenter(R.layout.lb_header)); 94 HeadersFragment()95 public HeadersFragment() { 96 setPresenterSelector(sHeaderPresenter); 97 FocusHighlightHelper.setupHeaderItemFocusHighlight(getBridgeAdapter()); 98 } 99 setOnHeaderClickedListener(OnHeaderClickedListener listener)100 public void setOnHeaderClickedListener(OnHeaderClickedListener listener) { 101 mOnHeaderClickedListener = listener; 102 } 103 setOnHeaderViewSelectedListener(OnHeaderViewSelectedListener listener)104 public void setOnHeaderViewSelectedListener(OnHeaderViewSelectedListener listener) { 105 mOnHeaderViewSelectedListener = listener; 106 } 107 108 @Override findGridViewFromRoot(View view)109 VerticalGridView findGridViewFromRoot(View view) { 110 return (VerticalGridView) view.findViewById(R.id.browse_headers); 111 } 112 113 @Override onRowSelected(RecyclerView parent, RecyclerView.ViewHolder viewHolder, int position, int subposition)114 void onRowSelected(RecyclerView parent, RecyclerView.ViewHolder viewHolder, 115 int position, int subposition) { 116 if (mOnHeaderViewSelectedListener != null) { 117 if (viewHolder != null && position >= 0) { 118 ItemBridgeAdapter.ViewHolder vh = (ItemBridgeAdapter.ViewHolder) viewHolder; 119 mOnHeaderViewSelectedListener.onHeaderSelected( 120 (RowHeaderPresenter.ViewHolder) vh.getViewHolder(), (Row) vh.getItem()); 121 } else { 122 mOnHeaderViewSelectedListener.onHeaderSelected(null, null); 123 } 124 } 125 } 126 127 private final ItemBridgeAdapter.AdapterListener mAdapterListener = 128 new ItemBridgeAdapter.AdapterListener() { 129 @Override 130 public void onCreate(final ItemBridgeAdapter.ViewHolder viewHolder) { 131 View headerView = viewHolder.getViewHolder().view; 132 headerView.setOnClickListener(new View.OnClickListener() { 133 @Override 134 public void onClick(View v) { 135 if (mOnHeaderClickedListener != null) { 136 mOnHeaderClickedListener.onHeaderClicked( 137 (RowHeaderPresenter.ViewHolder) viewHolder.getViewHolder(), 138 (Row) viewHolder.getItem()); 139 } 140 } 141 }); 142 if (mWrapper != null) { 143 viewHolder.itemView.addOnLayoutChangeListener(sLayoutChangeListener); 144 } else { 145 headerView.addOnLayoutChangeListener(sLayoutChangeListener); 146 } 147 } 148 149 }; 150 151 static OnLayoutChangeListener sLayoutChangeListener = new OnLayoutChangeListener() { 152 @Override 153 public void onLayoutChange(View v, int left, int top, int right, int bottom, 154 int oldLeft, int oldTop, int oldRight, int oldBottom) { 155 v.setPivotX(v.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? v.getWidth() : 0); 156 v.setPivotY(v.getMeasuredHeight() / 2); 157 } 158 }; 159 160 @Override getLayoutResourceId()161 int getLayoutResourceId() { 162 return R.layout.lb_headers_fragment; 163 } 164 165 @Override onViewCreated(View view, Bundle savedInstanceState)166 public void onViewCreated(View view, Bundle savedInstanceState) { 167 super.onViewCreated(view, savedInstanceState); 168 final VerticalGridView listView = getVerticalGridView(); 169 if (listView == null) { 170 return; 171 } 172 if (mBackgroundColorSet) { 173 listView.setBackgroundColor(mBackgroundColor); 174 updateFadingEdgeToBrandColor(mBackgroundColor); 175 } else { 176 Drawable d = listView.getBackground(); 177 if (d instanceof ColorDrawable) { 178 updateFadingEdgeToBrandColor(((ColorDrawable) d).getColor()); 179 } 180 } 181 updateListViewVisibility(); 182 } 183 updateListViewVisibility()184 private void updateListViewVisibility() { 185 final VerticalGridView listView = getVerticalGridView(); 186 if (listView != null) { 187 getView().setVisibility(mHeadersGone ? View.GONE : View.VISIBLE); 188 if (!mHeadersGone) { 189 if (mHeadersEnabled) { 190 listView.setChildrenVisibility(View.VISIBLE); 191 } else { 192 listView.setChildrenVisibility(View.INVISIBLE); 193 } 194 } 195 } 196 } 197 setHeadersEnabled(boolean enabled)198 void setHeadersEnabled(boolean enabled) { 199 mHeadersEnabled = enabled; 200 updateListViewVisibility(); 201 } 202 setHeadersGone(boolean gone)203 void setHeadersGone(boolean gone) { 204 mHeadersGone = gone; 205 updateListViewVisibility(); 206 } 207 208 static class NoOverlappingFrameLayout extends FrameLayout { 209 NoOverlappingFrameLayout(Context context)210 public NoOverlappingFrameLayout(Context context) { 211 super(context); 212 } 213 214 /** 215 * Avoid creating hardware layer for header dock. 216 */ 217 @Override hasOverlappingRendering()218 public boolean hasOverlappingRendering() { 219 return false; 220 } 221 } 222 223 // Wrapper needed because of conflict between RecyclerView's use of alpha 224 // for ADD animations, and RowHeaderPresenter's use of alpha for selected level. 225 final ItemBridgeAdapter.Wrapper mWrapper = new ItemBridgeAdapter.Wrapper() { 226 @Override 227 public void wrap(View wrapper, View wrapped) { 228 ((FrameLayout) wrapper).addView(wrapped); 229 } 230 231 @Override 232 public View createWrapper(View root) { 233 return new NoOverlappingFrameLayout(root.getContext()); 234 } 235 }; 236 @Override updateAdapter()237 void updateAdapter() { 238 super.updateAdapter(); 239 ItemBridgeAdapter adapter = getBridgeAdapter(); 240 adapter.setAdapterListener(mAdapterListener); 241 adapter.setWrapper(mWrapper); 242 } 243 setBackgroundColor(int color)244 void setBackgroundColor(int color) { 245 mBackgroundColor = color; 246 mBackgroundColorSet = true; 247 248 if (getVerticalGridView() != null) { 249 getVerticalGridView().setBackgroundColor(mBackgroundColor); 250 updateFadingEdgeToBrandColor(mBackgroundColor); 251 } 252 } 253 updateFadingEdgeToBrandColor(int backgroundColor)254 private void updateFadingEdgeToBrandColor(int backgroundColor) { 255 View fadingView = getView().findViewById(R.id.fade_out_edge); 256 Drawable background = fadingView.getBackground(); 257 if (background instanceof GradientDrawable) { 258 background.mutate(); 259 ((GradientDrawable) background).setColors( 260 new int[] {Color.TRANSPARENT, backgroundColor}); 261 } 262 } 263 264 @Override onTransitionStart()265 public void onTransitionStart() { 266 super.onTransitionStart(); 267 if (!mHeadersEnabled) { 268 // When enabling headers fragment, the RowHeaderView gets a focus but 269 // isShown() is still false because its parent is INVISIBLE, accessibility 270 // event is not sent. 271 // Workaround is: prevent focus to a child view during transition and put 272 // focus on it after transition is done. 273 final VerticalGridView listView = getVerticalGridView(); 274 if (listView != null) { 275 listView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS); 276 if (listView.hasFocus()) { 277 listView.requestFocus(); 278 } 279 } 280 } 281 } 282 283 @Override onTransitionEnd()284 public void onTransitionEnd() { 285 if (mHeadersEnabled) { 286 final VerticalGridView listView = getVerticalGridView(); 287 if (listView != null) { 288 listView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); 289 if (listView.hasFocus()) { 290 listView.requestFocus(); 291 } 292 } 293 } 294 super.onTransitionEnd(); 295 } 296 isScrolling()297 public boolean isScrolling() { 298 return getVerticalGridView().getScrollState() 299 != HorizontalGridView.SCROLL_STATE_IDLE; 300 } 301 } 302