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