GlifRecyclerLayout.java revision 5a4d6cdfb63240c41527ba80b7baddba8933d770
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);
84b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam            setAdapter(new RecyclerItemAdapter(inflated));
85b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        }
86180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        int dividerInset =
87180360409c9e4e9163c670ff48663244b4057eafMaurice Lam                a.getDimensionPixelSize(R.styleable.SuwGlifRecyclerLayout_suwDividerInset, 0);
88180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        if (dividerInset == 0) {
89180360409c9e4e9163c670ff48663244b4057eafMaurice Lam            dividerInset = getResources()
90180360409c9e4e9163c670ff48663244b4057eafMaurice Lam                    .getDimensionPixelSize(R.dimen.suw_items_icon_divider_inset);
91180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        }
92180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        setDividerInset(dividerInset);
93b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        a.recycle();
94b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    }
95b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
96b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    @Override
97180360409c9e4e9163c670ff48663244b4057eafMaurice Lam    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
98180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        super.onLayout(changed, left, top, right, bottom);
99180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        if (mDivider == null) {
100180360409c9e4e9163c670ff48663244b4057eafMaurice Lam            // Update divider in case layout direction has just been resolved
101180360409c9e4e9163c670ff48663244b4057eafMaurice Lam            updateDivider();
102180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        }
103180360409c9e4e9163c670ff48663244b4057eafMaurice Lam    }
104180360409c9e4e9163c670ff48663244b4057eafMaurice Lam
105180360409c9e4e9163c670ff48663244b4057eafMaurice Lam    @Override
106b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    protected View onInflateTemplate(LayoutInflater inflater, int template) {
107b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        if (template == 0) {
108b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam            template = R.layout.suw_glif_recycler_template;
109b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        }
110b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        return super.onInflateTemplate(inflater, template);
111b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    }
112b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
113b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    @Override
114b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    protected ViewGroup findContainer(int containerId) {
115b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        if (containerId == 0) {
116b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam            containerId = R.id.suw_recycler_view;
117b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        }
118b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        return super.findContainer(containerId);
119b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    }
120b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
121b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    @Override
122b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    protected void onTemplateInflated() {
123180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        final Context context = getContext();
124b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        mRecyclerView = (RecyclerView) findViewById(R.id.suw_recycler_view);
125180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        mRecyclerView.setLayoutManager(new LinearLayoutManager(context));
126b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        if (mRecyclerView instanceof HeaderRecyclerView) {
127b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam            final View header = ((HeaderRecyclerView) mRecyclerView).getHeader();
128b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam            mHeaderTextView = (TextView) header.findViewById(R.id.suw_layout_title);
129b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam            mIconView = (ImageView) header.findViewById(R.id.suw_layout_icon);
130b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        }
131180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        mDividerDecoration = DividerItemDecoration.getDefault(context);
132180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        mRecyclerView.addItemDecoration(mDividerDecoration);
133b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    }
134b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
135b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    @Override
136b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    protected TextView getHeaderTextView() {
137b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        return mHeaderTextView;
138b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    }
139b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
140b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    @Override
141b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    protected ImageView getIconView() {
142b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        return mIconView;
143b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    }
144b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
145b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    public RecyclerView getRecyclerView() {
146b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        return mRecyclerView;
147b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    }
148b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
149b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    public void setAdapter(RecyclerView.Adapter adapter) {
150b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam        getRecyclerView().setAdapter(adapter);
151b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    }
152b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam
153b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    public RecyclerView.Adapter getAdapter() {
1545a4d6cdfb63240c41527ba80b7baddba8933d770Maurice Lam        final RecyclerView.Adapter adapter = getRecyclerView().getAdapter();
1555a4d6cdfb63240c41527ba80b7baddba8933d770Maurice Lam        if (adapter instanceof HeaderRecyclerView.HeaderAdapter) {
1565a4d6cdfb63240c41527ba80b7baddba8933d770Maurice Lam            return ((HeaderRecyclerView.HeaderAdapter) adapter).getWrappedAdapter();
1575a4d6cdfb63240c41527ba80b7baddba8933d770Maurice Lam        }
1585a4d6cdfb63240c41527ba80b7baddba8933d770Maurice Lam        return adapter;
159b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam    }
160180360409c9e4e9163c670ff48663244b4057eafMaurice Lam
161180360409c9e4e9163c670ff48663244b4057eafMaurice Lam    /**
162180360409c9e4e9163c670ff48663244b4057eafMaurice Lam     * Sets the start inset of the divider. This will use the default divider drawable set in the
163180360409c9e4e9163c670ff48663244b4057eafMaurice Lam     * theme and inset it {@code inset} pixels to the right (or left in RTL layouts).
164180360409c9e4e9163c670ff48663244b4057eafMaurice Lam     *
165180360409c9e4e9163c670ff48663244b4057eafMaurice Lam     * @param inset The number of pixels to inset on the "start" side of the list divider. Typically
166180360409c9e4e9163c670ff48663244b4057eafMaurice Lam     *              this will be either {@code @dimen/suw_items_icon_divider_inset} or
167180360409c9e4e9163c670ff48663244b4057eafMaurice Lam     *              {@code @dimen/suw_items_text_divider_inset}.
168180360409c9e4e9163c670ff48663244b4057eafMaurice Lam     */
169180360409c9e4e9163c670ff48663244b4057eafMaurice Lam    public void setDividerInset(int inset) {
170180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        mDividerInset = inset;
171180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        updateDivider();
172180360409c9e4e9163c670ff48663244b4057eafMaurice Lam    }
173180360409c9e4e9163c670ff48663244b4057eafMaurice Lam
174180360409c9e4e9163c670ff48663244b4057eafMaurice Lam    public int getDividerInset() {
175180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        return mDividerInset;
176180360409c9e4e9163c670ff48663244b4057eafMaurice Lam    }
177180360409c9e4e9163c670ff48663244b4057eafMaurice Lam
178180360409c9e4e9163c670ff48663244b4057eafMaurice Lam    private void updateDivider() {
179180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        boolean shouldUpdate = true;
180180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        if (Build.VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
181180360409c9e4e9163c670ff48663244b4057eafMaurice Lam            shouldUpdate = isLayoutDirectionResolved();
182180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        }
183180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        if (shouldUpdate) {
184180360409c9e4e9163c670ff48663244b4057eafMaurice Lam            if (mDefaultDivider == null) {
185180360409c9e4e9163c670ff48663244b4057eafMaurice Lam                mDefaultDivider = mDividerDecoration.getDivider();
186180360409c9e4e9163c670ff48663244b4057eafMaurice Lam            }
187180360409c9e4e9163c670ff48663244b4057eafMaurice Lam            mDivider = DrawableLayoutDirectionHelper.createRelativeInsetDrawable(mDefaultDivider,
188180360409c9e4e9163c670ff48663244b4057eafMaurice Lam                    mDividerInset /* start */, 0 /* top */, 0 /* end */, 0 /* bottom */, this);
189180360409c9e4e9163c670ff48663244b4057eafMaurice Lam            mDividerDecoration.setDivider(mDivider);
190180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        }
191180360409c9e4e9163c670ff48663244b4057eafMaurice Lam    }
192180360409c9e4e9163c670ff48663244b4057eafMaurice Lam
193180360409c9e4e9163c670ff48663244b4057eafMaurice Lam    public Drawable getDivider() {
194180360409c9e4e9163c670ff48663244b4057eafMaurice Lam        return mDivider;
195180360409c9e4e9163c670ff48663244b4057eafMaurice Lam    }
196b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam}
197