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.Drawable; 22import android.graphics.drawable.GradientDrawable; 23import android.os.Bundle; 24import android.support.v17.leanback.R; 25import android.support.v17.leanback.widget.FocusHighlightHelper; 26import android.support.v17.leanback.widget.ItemBridgeAdapter; 27import android.support.v17.leanback.widget.PresenterSelector; 28import android.support.v17.leanback.widget.OnItemViewSelectedListener; 29import android.support.v17.leanback.widget.Row; 30import android.support.v17.leanback.widget.RowHeaderPresenter; 31import android.support.v17.leanback.widget.SinglePresenterSelector; 32import android.support.v17.leanback.widget.VerticalGridView; 33import android.support.v7.widget.RecyclerView; 34import android.util.TypedValue; 35import android.view.View; 36import android.view.ViewGroup; 37import android.view.View.OnLayoutChangeListener; 38import android.widget.FrameLayout; 39 40/** 41 * An internal fragment containing a list of row headers. 42 */ 43public class HeadersSupportFragment extends BaseRowSupportFragment { 44 45 interface OnHeaderClickedListener { 46 void onHeaderClicked(); 47 } 48 49 interface OnHeaderViewSelectedListener { 50 void onHeaderSelected(RowHeaderPresenter.ViewHolder viewHolder, Row row); 51 } 52 53 private OnHeaderViewSelectedListener mOnHeaderViewSelectedListener; 54 private OnHeaderClickedListener mOnHeaderClickedListener; 55 private boolean mHeadersEnabled = true; 56 private boolean mHeadersGone = false; 57 private int mBackgroundColor; 58 private boolean mBackgroundColorSet; 59 60 private static final PresenterSelector sHeaderPresenter = new SinglePresenterSelector( 61 new RowHeaderPresenter(R.layout.lb_header)); 62 63 public HeadersSupportFragment() { 64 setPresenterSelector(sHeaderPresenter); 65 } 66 67 public void setOnHeaderClickedListener(OnHeaderClickedListener listener) { 68 mOnHeaderClickedListener = listener; 69 } 70 71 public void setOnHeaderViewSelectedListener(OnHeaderViewSelectedListener listener) { 72 mOnHeaderViewSelectedListener = listener; 73 } 74 75 @Override 76 VerticalGridView findGridViewFromRoot(View view) { 77 return (VerticalGridView) view.findViewById(R.id.browse_headers); 78 } 79 80 @Override 81 void onRowSelected(RecyclerView parent, RecyclerView.ViewHolder viewHolder, 82 int position, int subposition) { 83 if (mOnHeaderViewSelectedListener != null) { 84 if (viewHolder != null && position >= 0) { 85 Row row = (Row) getAdapter().get(position); 86 ItemBridgeAdapter.ViewHolder vh = (ItemBridgeAdapter.ViewHolder) viewHolder; 87 mOnHeaderViewSelectedListener.onHeaderSelected( 88 (RowHeaderPresenter.ViewHolder) vh.getViewHolder(), row); 89 } else { 90 mOnHeaderViewSelectedListener.onHeaderSelected(null, null); 91 } 92 } 93 } 94 95 private final ItemBridgeAdapter.AdapterListener mAdapterListener = 96 new ItemBridgeAdapter.AdapterListener() { 97 @Override 98 public void onCreate(ItemBridgeAdapter.ViewHolder viewHolder) { 99 View headerView = viewHolder.getViewHolder().view; 100 headerView.setOnClickListener(new View.OnClickListener() { 101 @Override 102 public void onClick(View v) { 103 if (mOnHeaderClickedListener != null) { 104 mOnHeaderClickedListener.onHeaderClicked(); 105 } 106 } 107 }); 108 headerView.setFocusable(true); 109 headerView.setFocusableInTouchMode(true); 110 if (mWrapper != null) { 111 viewHolder.itemView.addOnLayoutChangeListener(sLayoutChangeListener); 112 } else { 113 headerView.addOnLayoutChangeListener(sLayoutChangeListener); 114 } 115 } 116 117 }; 118 119 private static OnLayoutChangeListener sLayoutChangeListener = new OnLayoutChangeListener() { 120 @Override 121 public void onLayoutChange(View v, int left, int top, int right, int bottom, 122 int oldLeft, int oldTop, int oldRight, int oldBottom) { 123 v.setPivotX(v.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? v.getWidth() : 0); 124 v.setPivotY(v.getMeasuredHeight() / 2); 125 } 126 }; 127 128 @Override 129 int getLayoutResourceId() { 130 return R.layout.lb_headers_fragment; 131 } 132 133 @Override 134 public void onViewCreated(View view, Bundle savedInstanceState) { 135 super.onViewCreated(view, savedInstanceState); 136 final VerticalGridView listView = getVerticalGridView(); 137 if (listView == null) { 138 return; 139 } 140 if (getBridgeAdapter() != null) { 141 FocusHighlightHelper.setupHeaderItemFocusHighlight(listView); 142 } 143 view.setBackgroundColor(getBackgroundColor()); 144 updateFadingEdgeToBrandColor(getBackgroundColor()); 145 updateListViewVisibility(); 146 } 147 148 private void updateListViewVisibility() { 149 final VerticalGridView listView = getVerticalGridView(); 150 if (listView != null) { 151 getView().setVisibility(mHeadersGone ? View.GONE : View.VISIBLE); 152 if (!mHeadersGone) { 153 if (mHeadersEnabled) { 154 listView.setChildrenVisibility(View.VISIBLE); 155 } else { 156 listView.setChildrenVisibility(View.INVISIBLE); 157 } 158 } 159 } 160 } 161 162 void setHeadersEnabled(boolean enabled) { 163 mHeadersEnabled = enabled; 164 updateListViewVisibility(); 165 } 166 167 void setHeadersGone(boolean gone) { 168 mHeadersGone = gone; 169 updateListViewVisibility(); 170 } 171 172 static class NoOverlappingFrameLayout extends FrameLayout { 173 174 public NoOverlappingFrameLayout(Context context) { 175 super(context); 176 } 177 178 /** 179 * Avoid creating hardware layer for header dock. 180 */ 181 @Override 182 public boolean hasOverlappingRendering() { 183 return false; 184 } 185 } 186 187 // Wrapper needed because of conflict between RecyclerView's use of alpha 188 // for ADD animations, and RowHeaderPresnter's use of alpha for selected level. 189 private final ItemBridgeAdapter.Wrapper mWrapper = new ItemBridgeAdapter.Wrapper() { 190 @Override 191 public void wrap(View wrapper, View wrapped) { 192 ((FrameLayout) wrapper).addView(wrapped); 193 } 194 195 @Override 196 public View createWrapper(View root) { 197 return new NoOverlappingFrameLayout(root.getContext()); 198 } 199 }; 200 @Override 201 void updateAdapter() { 202 super.updateAdapter(); 203 ItemBridgeAdapter adapter = getBridgeAdapter(); 204 if (adapter != null) { 205 adapter.setAdapterListener(mAdapterListener); 206 adapter.setWrapper(mWrapper); 207 } 208 if (adapter != null && getVerticalGridView() != null) { 209 FocusHighlightHelper.setupHeaderItemFocusHighlight(getVerticalGridView()); 210 } 211 } 212 213 void setBackgroundColor(int color) { 214 mBackgroundColor = color; 215 mBackgroundColorSet = true; 216 217 if (getView() != null) { 218 getView().setBackgroundColor(mBackgroundColor); 219 updateFadingEdgeToBrandColor(mBackgroundColor); 220 } 221 } 222 223 private void updateFadingEdgeToBrandColor(int backgroundColor) { 224 View fadingView = getView().findViewById(R.id.fade_out_edge); 225 Drawable background = fadingView.getBackground(); 226 if (background instanceof GradientDrawable) { 227 background.mutate(); 228 ((GradientDrawable) background).setColors( 229 new int[] {Color.TRANSPARENT, backgroundColor}); 230 } 231 } 232 233 int getBackgroundColor() { 234 if (getActivity() == null) { 235 throw new IllegalStateException("Activity must be attached"); 236 } 237 238 if (mBackgroundColorSet) { 239 return mBackgroundColor; 240 } 241 242 TypedValue outValue = new TypedValue(); 243 if (getActivity().getTheme().resolveAttribute(R.attr.defaultBrandColor, outValue, true)) { 244 return getResources().getColor(outValue.resourceId); 245 } 246 return getResources().getColor(R.color.lb_default_brand_color); 247 } 248 249 @Override 250 void onTransitionStart() { 251 super.onTransitionStart(); 252 if (!mHeadersEnabled) { 253 // When enabling headers fragment, the RowHeaderView gets a focus but 254 // isShown() is still false because its parent is INVSIBILE, accessibility 255 // event is not sent. 256 // Workaround is: prevent focus to a child view during transition and put 257 // focus on it after transition is done. 258 final VerticalGridView listView = getVerticalGridView(); 259 if (listView != null) { 260 listView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS); 261 if (listView.hasFocus()) { 262 listView.requestFocus(); 263 } 264 } 265 } 266 } 267 268 @Override 269 void onTransitionEnd() { 270 if (mHeadersEnabled) { 271 final VerticalGridView listView = getVerticalGridView(); 272 if (listView != null) { 273 listView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); 274 if (listView.hasFocus()) { 275 listView.requestFocus(); 276 } 277 } 278 } 279 super.onTransitionEnd(); 280 } 281} 282