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