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 Lamimport android.widget.TextView; 313885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 323885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport com.android.setupwizardlib.items.ItemGroup; 333885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport com.android.setupwizardlib.items.ItemInflater; 343885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport com.android.setupwizardlib.items.RecyclerItemAdapter; 353885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport com.android.setupwizardlib.util.DrawableLayoutDirectionHelper; 363885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport com.android.setupwizardlib.util.RecyclerViewRequireScrollHelper; 373885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport com.android.setupwizardlib.view.HeaderRecyclerView; 383885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamimport com.android.setupwizardlib.view.NavigationBar; 393885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 403885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam/** 413885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * A setup wizard layout for use with {@link android.support.v7.widget.RecyclerView}. 423885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * {@code android:entries} can also be used to specify an 433885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * {@link com.android.setupwizardlib.items.ItemHierarchy} to be used with this layout in XML. 443885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * 453885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * @see SetupWizardItemsLayout 463885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam */ 473885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lampublic class SetupWizardRecyclerLayout extends SetupWizardLayout { 483885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 493885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam private static final String TAG = "RecyclerLayout"; 503885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 513885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam private RecyclerView.Adapter mAdapter; 523885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam private RecyclerView mRecyclerView; 53ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam private View mHeader; 543885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 553885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam private DividerItemDecoration mDividerDecoration; 563885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam private Drawable mDefaultDivider; 573885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam private Drawable mDivider; 583885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam private int mDividerInset; 593885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 603885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public SetupWizardRecyclerLayout(Context context) { 613885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam this(context, 0, 0); 623885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 633885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 643885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public SetupWizardRecyclerLayout(Context context, int template, int containerId) { 653885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam super(context, template, containerId); 663885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam init(context, null, 0); 673885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 683885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 693885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public SetupWizardRecyclerLayout(Context context, AttributeSet attrs) { 703885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam super(context, attrs); 713885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam init(context, attrs, 0); 723885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 733885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 743885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public SetupWizardRecyclerLayout(Context context, AttributeSet attrs, int defStyleAttr) { 753885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam super(context, attrs, defStyleAttr); 763885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam init(context, attrs, defStyleAttr); 773885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 783885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 793885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam private void init(Context context, AttributeSet attrs, int defStyleAttr) { 803885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam final TypedArray a = context.obtainStyledAttributes(attrs, 813885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam R.styleable.SuwSetupWizardRecyclerItemsLayout, defStyleAttr, 0); 823885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam final int xml = a.getResourceId( 833885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam R.styleable.SuwSetupWizardRecyclerItemsLayout_android_entries, 0); 843885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (xml != 0) { 853885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam final ItemGroup inflated = (ItemGroup) new ItemInflater(context).inflate(xml); 863885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mAdapter = new RecyclerItemAdapter(inflated); 873885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mAdapter.setHasStableIds(a.getBoolean( 883885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam R.styleable.SuwSetupWizardRecyclerItemsLayout_suwHasStableIds, false)); 893885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam setAdapter(mAdapter); 903885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 913885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam int dividerInset = a.getDimensionPixelSize( 923885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam R.styleable.SuwSetupWizardRecyclerItemsLayout_suwDividerInset, 0); 933885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (dividerInset == 0) { 943885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam dividerInset = getResources() 953885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam .getDimensionPixelSize(R.dimen.suw_items_icon_divider_inset); 963885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 973885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam setDividerInset(dividerInset); 983885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam a.recycle(); 993885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1003885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1013885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam @Override 1023885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 1033885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam super.onLayout(changed, left, top, right, bottom); 1043885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (mDivider == null) { 1053885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam // Update divider in case layout direction has just been resolved 1063885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam updateDivider(); 1073885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1083885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1093885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1103885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public RecyclerView.Adapter getAdapter() { 1113885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam return mAdapter; 1123885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1133885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1143885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public void setAdapter(RecyclerView.Adapter adapter) { 1153885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mAdapter = adapter; 1163885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam getRecyclerView().setAdapter(adapter); 1173885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1183885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1193885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public RecyclerView getRecyclerView() { 1203885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam return mRecyclerView; 1213885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1223885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1233885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam @Override 1243885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam protected ViewGroup findContainer(int containerId) { 1253885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (containerId == 0) { 1263885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam containerId = R.id.suw_recycler_view; 1273885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1283885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam return super.findContainer(containerId); 1293885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1303885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1313885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam @Override 1323885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam protected void onTemplateInflated() { 1333885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam initRecyclerView((RecyclerView) findViewById(R.id.suw_recycler_view)); 1343885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1353885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1363885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam protected void initRecyclerView(RecyclerView recyclerView) { 1373885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mRecyclerView = recyclerView; 1383885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); 1393885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (mRecyclerView instanceof HeaderRecyclerView) { 140ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam mHeader = ((HeaderRecyclerView) mRecyclerView).getHeader(); 1413885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1423885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mDividerDecoration = DividerItemDecoration.getDefault(getContext()); 1433885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mRecyclerView.addItemDecoration(mDividerDecoration); 1443885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1453885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1463885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam @Override 1473885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam protected View onInflateTemplate(LayoutInflater inflater, int template) { 1483885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (template == 0) { 1493885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam template = R.layout.suw_recycler_template; 1503885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1513885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam return super.onInflateTemplate(inflater, template); 1523885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1533885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1543885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam @Override 155ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam protected View findManagedViewById(int id) { 156ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam if (mHeader != null) { 157ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam final View view = mHeader.findViewById(id); 158ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam if (view != null) { 159ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam return view; 160ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam } 1613885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 162ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam return super.findViewById(id); 1633885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1643885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1653885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam @Override 1663885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public void requireScrollToBottom() { 1673885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam final NavigationBar navigationBar = getNavigationBar(); 1683885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam final RecyclerView recyclerView = getRecyclerView(); 1693885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (navigationBar != null && recyclerView != null) { 1703885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam RecyclerViewRequireScrollHelper.requireScroll(navigationBar, recyclerView); 1713885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } else { 1723885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam Log.e(TAG, "Both suw_layout_navigation_bar and suw_recycler_view must exist in" 1733885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam + " the template to require scrolling."); 1743885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1753885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1763885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1773885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam /** 1783885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * Sets the start inset of the divider. This will use the default divider drawable set in the 1793885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * theme and inset it {@code inset} pixels to the right (or left in RTL layouts). 1803885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * 1813885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * @param inset The number of pixels to inset on the "start" side of the list divider. Typically 1823885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * this will be either {@code @dimen/suw_items_icon_divider_inset} or 1833885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * {@code @dimen/suw_items_text_divider_inset}. 1843885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam */ 1853885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public void setDividerInset(int inset) { 1863885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mDividerInset = inset; 1873885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam updateDivider(); 1883885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1893885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1903885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public int getDividerInset() { 1913885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam return mDividerInset; 1923885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1933885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 1943885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam private void updateDivider() { 1953885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam boolean shouldUpdate = true; 1963885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 1973885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam shouldUpdate = isLayoutDirectionResolved(); 1983885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 1993885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (shouldUpdate) { 2003885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam if (mDefaultDivider == null) { 2013885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mDefaultDivider = mDividerDecoration.getDivider(); 2023885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 2033885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mDivider = DrawableLayoutDirectionHelper.createRelativeInsetDrawable(mDefaultDivider, 2043885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mDividerInset /* start */, 0 /* top */, 0 /* end */, 0 /* bottom */, this); 2053885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam mDividerDecoration.setDivider(mDivider); 2063885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 2073885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 2083885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam 2093885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam public Drawable getDivider() { 2103885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam return mDivider; 2113885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam } 2123885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam} 213