GlifRecyclerLayout.java revision 2286e48a268aaa0dc57b93b878c3a632c627acec
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 Lamimport android.widget.ImageView;
32b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.widget.TextView;
33b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
34b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport com.android.setupwizardlib.items.ItemGroup;
35b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport com.android.setupwizardlib.items.ItemInflater;
36b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport com.android.setupwizardlib.items.RecyclerItemAdapter;
37180360409c9e4e9163c670ff48663244b4057eafMaurice Lamimport com.android.setupwizardlib.util.DrawableLayoutDirectionHelper;
38b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport com.android.setupwizardlib.view.HeaderRecyclerView;
39b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
40b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam/**
41b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * A GLIF themed layout with a RecyclerView. {@code android:entries} can also be used to specify an
42b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * {@link com.android.setupwizardlib.items.ItemHierarchy} to be used with this layout in XML.
43b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam */
44b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lampublic class GlifRecyclerLayout extends GlifLayout {
45b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
46b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    private RecyclerView mRecyclerView;
47b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    private TextView mHeaderTextView;
48b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    private ImageView mIconView;
49180360409c9e4e9163c670ff48663244b4057eafMaurice Lam    private DividerItemDecoration mDividerDecoration;
50180360409c9e4e9163c670ff48663244b4057eafMaurice Lam    private Drawable mDefaultDivider;
51180360409c9e4e9163c670ff48663244b4057eafMaurice Lam    private Drawable mDivider;
52180360409c9e4e9163c670ff48663244b4057eafMaurice Lam    private int mDividerInset;
53b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
54b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    public GlifRecyclerLayout(Context context) {
55b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        this(context, 0, 0);
56b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    }
57b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
58b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    public GlifRecyclerLayout(Context context, int template) {
59b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        this(context, template, 0);
60b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    }
61b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
62b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    public GlifRecyclerLayout(Context context, int template, int containerId) {
63b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        super(context, template, containerId);
64b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        init(context, null, 0);
65b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    }
66b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
67b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    public GlifRecyclerLayout(Context context, AttributeSet attrs) {
68b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        super(context, attrs);
69b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        init(context, attrs, 0);
70b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    }
71b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
72b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    @TargetApi(VERSION_CODES.HONEYCOMB)
73b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    public GlifRecyclerLayout(Context context, AttributeSet attrs, int defStyleAttr) {
74b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        super(context, attrs, defStyleAttr);
75b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        init(context, attrs, defStyleAttr);
76b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    }
77b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
78b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
79b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        final TypedArray a = context.obtainStyledAttributes(attrs,
80b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam                R.styleable.SuwGlifRecyclerLayout, defStyleAttr, 0);
81b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        final int xml = a.getResourceId(R.styleable.SuwGlifRecyclerLayout_android_entries, 0);
82b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        if (xml != 0) {
83b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam            final ItemGroup inflated = (ItemGroup) new ItemInflater(context).inflate(xml);
842286e48a268aaa0dc57b93b878c3a632c627acecUdam Saini            RecyclerItemAdapter adapter = new RecyclerItemAdapter(inflated);
852286e48a268aaa0dc57b93b878c3a632c627acecUdam Saini            adapter.setHasStableIds(a.getBoolean(
862286e48a268aaa0dc57b93b878c3a632c627acecUdam Saini                    R.styleable.SuwGlifRecyclerLayout_suwHasStableIds, false));
872286e48a268aaa0dc57b93b878c3a632c627acecUdam Saini            setAdapter(adapter);
88b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        }
89180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        int dividerInset =
90180360409c9e4e9163c670ff48663244b4057eafMaurice Lam                a.getDimensionPixelSize(R.styleable.SuwGlifRecyclerLayout_suwDividerInset, 0);
91180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        if (dividerInset == 0) {
92180360409c9e4e9163c670ff48663244b4057eafMaurice Lam            dividerInset = getResources()
93180360409c9e4e9163c670ff48663244b4057eafMaurice Lam                    .getDimensionPixelSize(R.dimen.suw_items_icon_divider_inset);
94180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        }
95180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        setDividerInset(dividerInset);
96b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        a.recycle();
97b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    }
98b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
99b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    @Override
100180360409c9e4e9163c670ff48663244b4057eafMaurice Lam    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
101180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        super.onLayout(changed, left, top, right, bottom);
102180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        if (mDivider == null) {
103180360409c9e4e9163c670ff48663244b4057eafMaurice Lam            // Update divider in case layout direction has just been resolved
104180360409c9e4e9163c670ff48663244b4057eafMaurice Lam            updateDivider();
105180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        }
106180360409c9e4e9163c670ff48663244b4057eafMaurice Lam    }
107180360409c9e4e9163c670ff48663244b4057eafMaurice Lam
108180360409c9e4e9163c670ff48663244b4057eafMaurice Lam    @Override
109b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    protected View onInflateTemplate(LayoutInflater inflater, int template) {
110b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        if (template == 0) {
111b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam            template = R.layout.suw_glif_recycler_template;
112b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        }
113b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        return super.onInflateTemplate(inflater, template);
114b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    }
115b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
116b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    @Override
117b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    protected ViewGroup findContainer(int containerId) {
118b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        if (containerId == 0) {
119b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam            containerId = R.id.suw_recycler_view;
120b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        }
121b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        return super.findContainer(containerId);
122b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    }
123b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
124b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    @Override
125b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    protected void onTemplateInflated() {
126180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        final Context context = getContext();
127b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        mRecyclerView = (RecyclerView) findViewById(R.id.suw_recycler_view);
128180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        mRecyclerView.setLayoutManager(new LinearLayoutManager(context));
129b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        if (mRecyclerView instanceof HeaderRecyclerView) {
130b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam            final View header = ((HeaderRecyclerView) mRecyclerView).getHeader();
131b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam            mHeaderTextView = (TextView) header.findViewById(R.id.suw_layout_title);
132b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam            mIconView = (ImageView) header.findViewById(R.id.suw_layout_icon);
133b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        }
134180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        mDividerDecoration = DividerItemDecoration.getDefault(context);
135180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        mRecyclerView.addItemDecoration(mDividerDecoration);
136b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    }
137b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
138b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    @Override
139b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    protected TextView getHeaderTextView() {
140b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        return mHeaderTextView;
141b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    }
142b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
143b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    @Override
144b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    protected ImageView getIconView() {
145b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        return mIconView;
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
169180360409c9e4e9163c670ff48663244b4057eafMaurice Lam     *              this will be either {@code @dimen/suw_items_icon_divider_inset} or
170180360409c9e4e9163c670ff48663244b4057eafMaurice Lam     *              {@code @dimen/suw_items_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