1b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam/* 2b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * Copyright (C) 2015 The Android Open Source Project 3b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * 4b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * Licensed under the Apache License, Version 2.0 (the "License"); 5b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * you may not use this file except in compliance with the License. 6b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * You may obtain a copy of the License at 7b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * 8b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * http://www.apache.org/licenses/LICENSE-2.0 9b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * 10b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * Unless required by applicable law or agreed to in writing, software 11b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * distributed under the License is distributed on an "AS IS" BASIS, 12b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * See the License for the specific language governing permissions and 14b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * limitations under the License. 15b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam */ 16b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 17b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lampackage com.android.setupwizardlib; 18b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 19b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.annotation.TargetApi; 20b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.content.Context; 21b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.content.res.TypedArray; 22180360409c9e4e9163c670ff48663244b4057eafMaurice Lamimport android.graphics.drawable.Drawable; 23180360409c9e4e9163c670ff48663244b4057eafMaurice Lamimport android.os.Build; 24b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.os.Build.VERSION_CODES; 25b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.support.v7.widget.LinearLayoutManager; 26b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.support.v7.widget.RecyclerView; 27b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.util.AttributeSet; 28b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.view.LayoutInflater; 29b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.view.View; 30b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.view.ViewGroup; 31b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 32b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport com.android.setupwizardlib.items.ItemGroup; 33b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport com.android.setupwizardlib.items.ItemInflater; 34b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport com.android.setupwizardlib.items.RecyclerItemAdapter; 35180360409c9e4e9163c670ff48663244b4057eafMaurice Lamimport com.android.setupwizardlib.util.DrawableLayoutDirectionHelper; 36b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport com.android.setupwizardlib.view.HeaderRecyclerView; 37b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 38b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam/** 39b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * A GLIF themed layout with a RecyclerView. {@code android:entries} can also be used to specify an 40b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * {@link com.android.setupwizardlib.items.ItemHierarchy} to be used with this layout in XML. 41b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam */ 42b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lampublic class GlifRecyclerLayout extends GlifLayout { 43b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 44b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam private RecyclerView mRecyclerView; 4584979a6b2874d09762404c3c8a902f4aad016d01Maurice Lam private View mHeader; 4684979a6b2874d09762404c3c8a902f4aad016d01Maurice Lam 47180360409c9e4e9163c670ff48663244b4057eafMaurice Lam private DividerItemDecoration mDividerDecoration; 48180360409c9e4e9163c670ff48663244b4057eafMaurice Lam private Drawable mDefaultDivider; 49180360409c9e4e9163c670ff48663244b4057eafMaurice Lam private Drawable mDivider; 50180360409c9e4e9163c670ff48663244b4057eafMaurice Lam private int mDividerInset; 51b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 52b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam public GlifRecyclerLayout(Context context) { 53b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam this(context, 0, 0); 54b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 55b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 56b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam public GlifRecyclerLayout(Context context, int template) { 57b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam this(context, template, 0); 58b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 59b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 60b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam public GlifRecyclerLayout(Context context, int template, int containerId) { 61b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam super(context, template, containerId); 62b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam init(context, null, 0); 63b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 64b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 65b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam public GlifRecyclerLayout(Context context, AttributeSet attrs) { 66b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam super(context, attrs); 67b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam init(context, attrs, 0); 68b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 69b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 70b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam @TargetApi(VERSION_CODES.HONEYCOMB) 71b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam public GlifRecyclerLayout(Context context, AttributeSet attrs, int defStyleAttr) { 72b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam super(context, attrs, defStyleAttr); 73b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam init(context, attrs, defStyleAttr); 74b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 75b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 76b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam private void init(Context context, AttributeSet attrs, int defStyleAttr) { 77b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam final TypedArray a = context.obtainStyledAttributes(attrs, 78b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam R.styleable.SuwGlifRecyclerLayout, defStyleAttr, 0); 79b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam final int xml = a.getResourceId(R.styleable.SuwGlifRecyclerLayout_android_entries, 0); 80b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam if (xml != 0) { 81b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam final ItemGroup inflated = (ItemGroup) new ItemInflater(context).inflate(xml); 822286e48a268aaa0dc57b93b878c3a632c627acecUdam Saini RecyclerItemAdapter adapter = new RecyclerItemAdapter(inflated); 832286e48a268aaa0dc57b93b878c3a632c627acecUdam Saini adapter.setHasStableIds(a.getBoolean( 842286e48a268aaa0dc57b93b878c3a632c627acecUdam Saini R.styleable.SuwGlifRecyclerLayout_suwHasStableIds, false)); 852286e48a268aaa0dc57b93b878c3a632c627acecUdam Saini setAdapter(adapter); 86b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 87180360409c9e4e9163c670ff48663244b4057eafMaurice Lam int dividerInset = 88180360409c9e4e9163c670ff48663244b4057eafMaurice Lam a.getDimensionPixelSize(R.styleable.SuwGlifRecyclerLayout_suwDividerInset, 0); 89180360409c9e4e9163c670ff48663244b4057eafMaurice Lam if (dividerInset == 0) { 90180360409c9e4e9163c670ff48663244b4057eafMaurice Lam dividerInset = getResources() 9115391fc05a0fc45e9af85b653abffa41df575e91Maurice Lam .getDimensionPixelSize(R.dimen.suw_items_glif_icon_divider_inset); 92180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 93180360409c9e4e9163c670ff48663244b4057eafMaurice Lam setDividerInset(dividerInset); 94b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam a.recycle(); 95b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 96b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 97b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam @Override 98180360409c9e4e9163c670ff48663244b4057eafMaurice Lam protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 99180360409c9e4e9163c670ff48663244b4057eafMaurice Lam super.onLayout(changed, left, top, right, bottom); 100180360409c9e4e9163c670ff48663244b4057eafMaurice Lam if (mDivider == null) { 101180360409c9e4e9163c670ff48663244b4057eafMaurice Lam // Update divider in case layout direction has just been resolved 102180360409c9e4e9163c670ff48663244b4057eafMaurice Lam updateDivider(); 103180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 104180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 105180360409c9e4e9163c670ff48663244b4057eafMaurice Lam 106180360409c9e4e9163c670ff48663244b4057eafMaurice Lam @Override 107b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam protected View onInflateTemplate(LayoutInflater inflater, int template) { 108b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam if (template == 0) { 109b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam template = R.layout.suw_glif_recycler_template; 110b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 111b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam return super.onInflateTemplate(inflater, template); 112b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 113b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 114b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam @Override 115b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam protected ViewGroup findContainer(int containerId) { 116b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam if (containerId == 0) { 117b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam containerId = R.id.suw_recycler_view; 118b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 119b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam return super.findContainer(containerId); 120b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 121b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 122b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam @Override 123b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam protected void onTemplateInflated() { 12484979a6b2874d09762404c3c8a902f4aad016d01Maurice Lam initRecyclerView((RecyclerView) findViewById(R.id.suw_recycler_view)); 12584979a6b2874d09762404c3c8a902f4aad016d01Maurice Lam } 12684979a6b2874d09762404c3c8a902f4aad016d01Maurice Lam 12784979a6b2874d09762404c3c8a902f4aad016d01Maurice Lam protected void initRecyclerView(RecyclerView recyclerView) { 12884979a6b2874d09762404c3c8a902f4aad016d01Maurice Lam mRecyclerView = recyclerView; 12984979a6b2874d09762404c3c8a902f4aad016d01Maurice Lam mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); 130b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam if (mRecyclerView instanceof HeaderRecyclerView) { 13184979a6b2874d09762404c3c8a902f4aad016d01Maurice Lam mHeader = ((HeaderRecyclerView) mRecyclerView).getHeader(); 132b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 13384979a6b2874d09762404c3c8a902f4aad016d01Maurice Lam mDividerDecoration = DividerItemDecoration.getDefault(getContext()); 134180360409c9e4e9163c670ff48663244b4057eafMaurice Lam mRecyclerView.addItemDecoration(mDividerDecoration); 135b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 136b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 137b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam @Override 13884979a6b2874d09762404c3c8a902f4aad016d01Maurice Lam protected View findManagedViewById(int id) { 13984979a6b2874d09762404c3c8a902f4aad016d01Maurice Lam if (mHeader != null) { 14084979a6b2874d09762404c3c8a902f4aad016d01Maurice Lam final View view = mHeader.findViewById(id); 14184979a6b2874d09762404c3c8a902f4aad016d01Maurice Lam if (view != null) { 14284979a6b2874d09762404c3c8a902f4aad016d01Maurice Lam return view; 14384979a6b2874d09762404c3c8a902f4aad016d01Maurice Lam } 14484979a6b2874d09762404c3c8a902f4aad016d01Maurice Lam } 14584979a6b2874d09762404c3c8a902f4aad016d01Maurice Lam return super.findViewById(id); 146b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 147b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 148b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam public RecyclerView getRecyclerView() { 149b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam return mRecyclerView; 150b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 151b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 152b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam public void setAdapter(RecyclerView.Adapter adapter) { 153b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam getRecyclerView().setAdapter(adapter); 154b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 155b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 156b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam public RecyclerView.Adapter getAdapter() { 1575a4d6cdfb63240c41527ba80b7baddba8933d770Maurice Lam final RecyclerView.Adapter adapter = getRecyclerView().getAdapter(); 1585a4d6cdfb63240c41527ba80b7baddba8933d770Maurice Lam if (adapter instanceof HeaderRecyclerView.HeaderAdapter) { 1595a4d6cdfb63240c41527ba80b7baddba8933d770Maurice Lam return ((HeaderRecyclerView.HeaderAdapter) adapter).getWrappedAdapter(); 1605a4d6cdfb63240c41527ba80b7baddba8933d770Maurice Lam } 1615a4d6cdfb63240c41527ba80b7baddba8933d770Maurice Lam return adapter; 162b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 163180360409c9e4e9163c670ff48663244b4057eafMaurice Lam 164180360409c9e4e9163c670ff48663244b4057eafMaurice Lam /** 165180360409c9e4e9163c670ff48663244b4057eafMaurice Lam * Sets the start inset of the divider. This will use the default divider drawable set in the 166180360409c9e4e9163c670ff48663244b4057eafMaurice Lam * theme and inset it {@code inset} pixels to the right (or left in RTL layouts). 167180360409c9e4e9163c670ff48663244b4057eafMaurice Lam * 168180360409c9e4e9163c670ff48663244b4057eafMaurice Lam * @param inset The number of pixels to inset on the "start" side of the list divider. Typically 16915391fc05a0fc45e9af85b653abffa41df575e91Maurice Lam * this will be either {@code @dimen/suw_items_glif_icon_divider_inset} or 17015391fc05a0fc45e9af85b653abffa41df575e91Maurice Lam * {@code @dimen/suw_items_glif_text_divider_inset}. 171180360409c9e4e9163c670ff48663244b4057eafMaurice Lam */ 172180360409c9e4e9163c670ff48663244b4057eafMaurice Lam public void setDividerInset(int inset) { 173180360409c9e4e9163c670ff48663244b4057eafMaurice Lam mDividerInset = inset; 174180360409c9e4e9163c670ff48663244b4057eafMaurice Lam updateDivider(); 175180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 176180360409c9e4e9163c670ff48663244b4057eafMaurice Lam 177180360409c9e4e9163c670ff48663244b4057eafMaurice Lam public int getDividerInset() { 178180360409c9e4e9163c670ff48663244b4057eafMaurice Lam return mDividerInset; 179180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 180180360409c9e4e9163c670ff48663244b4057eafMaurice Lam 181180360409c9e4e9163c670ff48663244b4057eafMaurice Lam private void updateDivider() { 182180360409c9e4e9163c670ff48663244b4057eafMaurice Lam boolean shouldUpdate = true; 183180360409c9e4e9163c670ff48663244b4057eafMaurice Lam if (Build.VERSION.SDK_INT >= VERSION_CODES.KITKAT) { 184180360409c9e4e9163c670ff48663244b4057eafMaurice Lam shouldUpdate = isLayoutDirectionResolved(); 185180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 186180360409c9e4e9163c670ff48663244b4057eafMaurice Lam if (shouldUpdate) { 187180360409c9e4e9163c670ff48663244b4057eafMaurice Lam if (mDefaultDivider == null) { 188180360409c9e4e9163c670ff48663244b4057eafMaurice Lam mDefaultDivider = mDividerDecoration.getDivider(); 189180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 190180360409c9e4e9163c670ff48663244b4057eafMaurice Lam mDivider = DrawableLayoutDirectionHelper.createRelativeInsetDrawable(mDefaultDivider, 191180360409c9e4e9163c670ff48663244b4057eafMaurice Lam mDividerInset /* start */, 0 /* top */, 0 /* end */, 0 /* bottom */, this); 192180360409c9e4e9163c670ff48663244b4057eafMaurice Lam mDividerDecoration.setDivider(mDivider); 193180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 194180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 195180360409c9e4e9163c670ff48663244b4057eafMaurice Lam 196180360409c9e4e9163c670ff48663244b4057eafMaurice Lam public Drawable getDivider() { 197180360409c9e4e9163c670ff48663244b4057eafMaurice Lam return mDivider; 198180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 199b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam} 200