13885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam/* 23885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * Copyright (C) 2015 The Android Open Source Project 33885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * 43885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * Licensed under the Apache License, Version 2.0 (the "License"); 53885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * you may not use this file except in compliance with the License. 63885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * You may obtain a copy of the License at 73885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * 83885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * http://www.apache.org/licenses/LICENSE-2.0 93885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * 103885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * Unless required by applicable law or agreed to in writing, software 113885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * distributed under the License is distributed on an "AS IS" BASIS, 123885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * See the License for the specific language governing permissions and 143885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * limitations under the License. 153885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam */ 163885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 173885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lampackage com.android.setupwizardlib; 183885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 193885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport android.content.Context; 203885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport android.content.res.TypedArray; 213885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport android.graphics.drawable.Drawable; 223885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport android.os.Build; 233885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport android.support.v7.widget.LinearLayoutManager; 243885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport android.support.v7.widget.RecyclerView; 253885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport android.util.AttributeSet; 263885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport android.util.Log; 273885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport android.view.LayoutInflater; 283885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport android.view.View; 293885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport android.view.ViewGroup; 303885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 313885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport com.android.setupwizardlib.items.ItemGroup; 323885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport com.android.setupwizardlib.items.ItemInflater; 333885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport com.android.setupwizardlib.items.RecyclerItemAdapter; 343885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport com.android.setupwizardlib.util.DrawableLayoutDirectionHelper; 353885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport com.android.setupwizardlib.util.RecyclerViewRequireScrollHelper; 363885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport com.android.setupwizardlib.view.HeaderRecyclerView; 373885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport com.android.setupwizardlib.view.NavigationBar; 383885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 393885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam/** 403885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * A setup wizard layout for use with {@link android.support.v7.widget.RecyclerView}. 413885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * {@code android:entries} can also be used to specify an 423885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * {@link com.android.setupwizardlib.items.ItemHierarchy} to be used with this layout in XML. 433885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * 443885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * @see SetupWizardItemsLayout 453885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam */ 463885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lampublic class SetupWizardRecyclerLayout extends SetupWizardLayout { 473885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 483885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam private static final String TAG = "RecyclerLayout"; 493885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 503885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam private RecyclerView.Adapter mAdapter; 513885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam private RecyclerView mRecyclerView; 52ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam private View mHeader; 533885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 543885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam private DividerItemDecoration mDividerDecoration; 553885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam private Drawable mDefaultDivider; 563885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam private Drawable mDivider; 573885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam private int mDividerInset; 583885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 593885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public SetupWizardRecyclerLayout(Context context) { 603885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam this(context, 0, 0); 613885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 623885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 633885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public SetupWizardRecyclerLayout(Context context, int template, int containerId) { 643885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam super(context, template, containerId); 653885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam init(context, null, 0); 663885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 673885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 683885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public SetupWizardRecyclerLayout(Context context, AttributeSet attrs) { 693885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam super(context, attrs); 703885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam init(context, attrs, 0); 713885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 723885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 733885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public SetupWizardRecyclerLayout(Context context, AttributeSet attrs, int defStyleAttr) { 743885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam super(context, attrs, defStyleAttr); 753885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam init(context, attrs, defStyleAttr); 763885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 773885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 783885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam private void init(Context context, AttributeSet attrs, int defStyleAttr) { 793885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam final TypedArray a = context.obtainStyledAttributes(attrs, 803885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam R.styleable.SuwSetupWizardRecyclerItemsLayout, defStyleAttr, 0); 813885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam final int xml = a.getResourceId( 823885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam R.styleable.SuwSetupWizardRecyclerItemsLayout_android_entries, 0); 833885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (xml != 0) { 843885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam final ItemGroup inflated = (ItemGroup) new ItemInflater(context).inflate(xml); 853885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mAdapter = new RecyclerItemAdapter(inflated); 863885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mAdapter.setHasStableIds(a.getBoolean( 873885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam R.styleable.SuwSetupWizardRecyclerItemsLayout_suwHasStableIds, false)); 883885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam setAdapter(mAdapter); 893885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 903885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam int dividerInset = a.getDimensionPixelSize( 913885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam R.styleable.SuwSetupWizardRecyclerItemsLayout_suwDividerInset, 0); 923885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (dividerInset == 0) { 933885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam dividerInset = getResources() 943885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam .getDimensionPixelSize(R.dimen.suw_items_icon_divider_inset); 953885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 963885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam setDividerInset(dividerInset); 973885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam a.recycle(); 983885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 993885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1003885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam @Override 1013885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 1023885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam super.onLayout(changed, left, top, right, bottom); 1033885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (mDivider == null) { 1043885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam // Update divider in case layout direction has just been resolved 1053885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam updateDivider(); 1063885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1073885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1083885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1093885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public RecyclerView.Adapter getAdapter() { 1103885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam return mAdapter; 1113885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1123885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1133885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public void setAdapter(RecyclerView.Adapter adapter) { 1143885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mAdapter = adapter; 1153885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam getRecyclerView().setAdapter(adapter); 1163885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1173885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1183885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public RecyclerView getRecyclerView() { 1193885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam return mRecyclerView; 1203885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1213885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1223885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam @Override 1233885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam protected ViewGroup findContainer(int containerId) { 1243885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (containerId == 0) { 1253885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam containerId = R.id.suw_recycler_view; 1263885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1273885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam return super.findContainer(containerId); 1283885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1293885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1303885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam @Override 1313885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam protected void onTemplateInflated() { 1323885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam initRecyclerView((RecyclerView) findViewById(R.id.suw_recycler_view)); 1333885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1343885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1353885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam protected void initRecyclerView(RecyclerView recyclerView) { 1363885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mRecyclerView = recyclerView; 1373885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); 1383885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (mRecyclerView instanceof HeaderRecyclerView) { 139ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam mHeader = ((HeaderRecyclerView) mRecyclerView).getHeader(); 1403885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 141325b78cfbd0d7366771ee81838bc444c69e39963Maurice Lam mDividerDecoration = new DividerItemDecoration(getContext()); 1423885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mRecyclerView.addItemDecoration(mDividerDecoration); 1433885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1443885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1453885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam @Override 1463885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam protected View onInflateTemplate(LayoutInflater inflater, int template) { 1473885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (template == 0) { 1483885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam template = R.layout.suw_recycler_template; 1493885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1503885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam return super.onInflateTemplate(inflater, template); 1513885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1523885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1533885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam @Override 154ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam protected View findManagedViewById(int id) { 155ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam if (mHeader != null) { 156ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam final View view = mHeader.findViewById(id); 157ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam if (view != null) { 158ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam return view; 159ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam } 1603885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 161ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam return super.findViewById(id); 1623885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1633885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1643885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam @Override 1653885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public void requireScrollToBottom() { 1663885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam final NavigationBar navigationBar = getNavigationBar(); 1673885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam final RecyclerView recyclerView = getRecyclerView(); 1683885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (navigationBar != null && recyclerView != null) { 1693885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam RecyclerViewRequireScrollHelper.requireScroll(navigationBar, recyclerView); 1703885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } else { 1713885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam Log.e(TAG, "Both suw_layout_navigation_bar and suw_recycler_view must exist in" 1723885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam + " the template to require scrolling."); 1733885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1743885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1753885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1763885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam /** 1773885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * Sets the start inset of the divider. This will use the default divider drawable set in the 1783885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * theme and inset it {@code inset} pixels to the right (or left in RTL layouts). 1793885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * 1803885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * @param inset The number of pixels to inset on the "start" side of the list divider. Typically 1813885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * this will be either {@code @dimen/suw_items_icon_divider_inset} or 1823885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * {@code @dimen/suw_items_text_divider_inset}. 1833885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam */ 1843885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public void setDividerInset(int inset) { 1853885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mDividerInset = inset; 1863885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam updateDivider(); 1873885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1883885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1893885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public int getDividerInset() { 1903885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam return mDividerInset; 1913885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1923885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1933885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam private void updateDivider() { 1943885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam boolean shouldUpdate = true; 1953885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 1963885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam shouldUpdate = isLayoutDirectionResolved(); 1973885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1983885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (shouldUpdate) { 1993885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (mDefaultDivider == null) { 2003885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mDefaultDivider = mDividerDecoration.getDivider(); 2013885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 2023885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mDivider = DrawableLayoutDirectionHelper.createRelativeInsetDrawable(mDefaultDivider, 2033885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mDividerInset /* start */, 0 /* top */, 0 /* end */, 0 /* bottom */, this); 2043885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mDividerDecoration.setDivider(mDivider); 2053885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 2063885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 2073885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 2083885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public Drawable getDivider() { 2093885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam return mDivider; 2103885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 2113885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam} 212