1d4c6ef70612f48c4612ec827bd89964d0955cd6fMaurice Lam/*
2d4c6ef70612f48c4612ec827bd89964d0955cd6fMaurice Lam * Copyright (C) 2015 The Android Open Source Project
3d4c6ef70612f48c4612ec827bd89964d0955cd6fMaurice Lam *
4d4c6ef70612f48c4612ec827bd89964d0955cd6fMaurice Lam * Licensed under the Apache License, Version 2.0 (the "License");
5d4c6ef70612f48c4612ec827bd89964d0955cd6fMaurice Lam * you may not use this file except in compliance with the License.
6d4c6ef70612f48c4612ec827bd89964d0955cd6fMaurice Lam * You may obtain a copy of the License at
7d4c6ef70612f48c4612ec827bd89964d0955cd6fMaurice Lam *
8d4c6ef70612f48c4612ec827bd89964d0955cd6fMaurice Lam *      http://www.apache.org/licenses/LICENSE-2.0
9d4c6ef70612f48c4612ec827bd89964d0955cd6fMaurice Lam *
10d4c6ef70612f48c4612ec827bd89964d0955cd6fMaurice Lam * Unless required by applicable law or agreed to in writing, software
11d4c6ef70612f48c4612ec827bd89964d0955cd6fMaurice Lam * distributed under the License is distributed on an "AS IS" BASIS,
12d4c6ef70612f48c4612ec827bd89964d0955cd6fMaurice Lam * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d4c6ef70612f48c4612ec827bd89964d0955cd6fMaurice Lam * See the License for the specific language governing permissions and
14d4c6ef70612f48c4612ec827bd89964d0955cd6fMaurice Lam * limitations under the License.
15d4c6ef70612f48c4612ec827bd89964d0955cd6fMaurice Lam */
16d4c6ef70612f48c4612ec827bd89964d0955cd6fMaurice Lam
17d4c6ef70612f48c4612ec827bd89964d0955cd6fMaurice Lampackage com.android.setupwizardlib;
18d4c6ef70612f48c4612ec827bd89964d0955cd6fMaurice Lam
1995af12dac219e6945bab6142ea3a4099077314aaMaurice Lamimport android.annotation.SuppressLint;
209f9367672191190f903955d09a4314d40869acc6Maurice Lamimport android.annotation.TargetApi;
2195af12dac219e6945bab6142ea3a4099077314aaMaurice Lamimport android.content.Context;
22bf4afac02228e42af171bbb5f3db11977be487b1Maurice Lamimport android.content.res.ColorStateList;
2395af12dac219e6945bab6142ea3a4099077314aaMaurice Lamimport android.content.res.TypedArray;
2495af12dac219e6945bab6142ea3a4099077314aaMaurice Lamimport android.graphics.Shader.TileMode;
2595af12dac219e6945bab6142ea3a4099077314aaMaurice Lamimport android.graphics.drawable.BitmapDrawable;
2695af12dac219e6945bab6142ea3a4099077314aaMaurice Lamimport android.graphics.drawable.Drawable;
2795af12dac219e6945bab6142ea3a4099077314aaMaurice Lamimport android.graphics.drawable.LayerDrawable;
28b8f3330e8be7da2f141b65967ecf3a2bad4e02a4Maurice Lamimport android.os.Build.VERSION;
29b8f3330e8be7da2f141b65967ecf3a2bad4e02a4Maurice Lamimport android.os.Build.VERSION_CODES;
30d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lamimport android.os.Parcel;
31d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lamimport android.os.Parcelable;
3295af12dac219e6945bab6142ea3a4099077314aaMaurice Lamimport android.util.AttributeSet;
332d77e072fed129b34e473c7f77246a2b064fab7dMaurice Lamimport android.util.Log;
347114577a094593dbf55b625146b3809800697030Jorim Jaggiimport android.util.TypedValue;
3595af12dac219e6945bab6142ea3a4099077314aaMaurice Lamimport android.view.Gravity;
3695af12dac219e6945bab6142ea3a4099077314aaMaurice Lamimport android.view.LayoutInflater;
3795af12dac219e6945bab6142ea3a4099077314aaMaurice Lamimport android.view.View;
3895af12dac219e6945bab6142ea3a4099077314aaMaurice Lamimport android.view.ViewGroup;
3995abb283deb209532bbbae4ade3f5cc149a548a6Maurice Lamimport android.widget.ScrollView;
4095af12dac219e6945bab6142ea3a4099077314aaMaurice Lamimport android.widget.TextView;
4195af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
427514f1cee29b3feb4822ce16945c1c312057d24fMaurice Lamimport com.android.setupwizardlib.template.HeaderMixin;
437514f1cee29b3feb4822ce16945c1c312057d24fMaurice Lamimport com.android.setupwizardlib.template.NavigationBarMixin;
447514f1cee29b3feb4822ce16945c1c312057d24fMaurice Lamimport com.android.setupwizardlib.template.ProgressBarMixin;
450ceb8d53e39ebb5bc103863787afb39ec5c41ad8Maurice Lamimport com.android.setupwizardlib.template.RequireScrollMixin;
460ceb8d53e39ebb5bc103863787afb39ec5c41ad8Maurice Lamimport com.android.setupwizardlib.template.ScrollViewScrollHandlingDelegate;
4795af12dac219e6945bab6142ea3a4099077314aaMaurice Lamimport com.android.setupwizardlib.view.Illustration;
487e5f0f0ea3b3075258cac9d26f90fd97c1a71dcaMaurice Lamimport com.android.setupwizardlib.view.NavigationBar;
4995af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
50bdfc0132ff90a333de202adfbf204cdc8139e632Maurice Lampublic class SetupWizardLayout extends TemplateLayout {
5195af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
5295af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    private static final String TAG = "SetupWizardLayout";
5395af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
5495af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    public SetupWizardLayout(Context context) {
55bdfc0132ff90a333de202adfbf204cdc8139e632Maurice Lam        super(context, 0, 0);
56bdfc0132ff90a333de202adfbf204cdc8139e632Maurice Lam        init(null, R.attr.suwLayoutTheme);
5795af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    }
5895af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
5995af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    public SetupWizardLayout(Context context, int template) {
60bdfc0132ff90a333de202adfbf204cdc8139e632Maurice Lam        this(context, template, 0);
61bdfc0132ff90a333de202adfbf204cdc8139e632Maurice Lam    }
62bdfc0132ff90a333de202adfbf204cdc8139e632Maurice Lam
63bdfc0132ff90a333de202adfbf204cdc8139e632Maurice Lam    public SetupWizardLayout(Context context, int template, int containerId) {
64bdfc0132ff90a333de202adfbf204cdc8139e632Maurice Lam        super(context, template, containerId);
65bdfc0132ff90a333de202adfbf204cdc8139e632Maurice Lam        init(null, R.attr.suwLayoutTheme);
6695af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    }
6795af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
6895af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    public SetupWizardLayout(Context context, AttributeSet attrs) {
699f9367672191190f903955d09a4314d40869acc6Maurice Lam        super(context, attrs);
70bdfc0132ff90a333de202adfbf204cdc8139e632Maurice Lam        init(attrs, R.attr.suwLayoutTheme);
7195af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    }
7295af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
739f9367672191190f903955d09a4314d40869acc6Maurice Lam    @TargetApi(VERSION_CODES.HONEYCOMB)
7495af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    public SetupWizardLayout(Context context, AttributeSet attrs, int defStyleAttr) {
759f9367672191190f903955d09a4314d40869acc6Maurice Lam        super(context, attrs, defStyleAttr);
76bdfc0132ff90a333de202adfbf204cdc8139e632Maurice Lam        init(attrs, defStyleAttr);
779f9367672191190f903955d09a4314d40869acc6Maurice Lam    }
789f9367672191190f903955d09a4314d40869acc6Maurice Lam
799f9367672191190f903955d09a4314d40869acc6Maurice Lam    // All the constructors delegate to this init method. The 3-argument constructor is not
809f9367672191190f903955d09a4314d40869acc6Maurice Lam    // available in LinearLayout before v11, so call super with the exact same arguments.
81bdfc0132ff90a333de202adfbf204cdc8139e632Maurice Lam    private void init(AttributeSet attrs, int defStyleAttr) {
827514f1cee29b3feb4822ce16945c1c312057d24fMaurice Lam        registerMixin(HeaderMixin.class, new HeaderMixin(this, attrs, defStyleAttr));
837514f1cee29b3feb4822ce16945c1c312057d24fMaurice Lam        registerMixin(ProgressBarMixin.class, new ProgressBarMixin(this));
847514f1cee29b3feb4822ce16945c1c312057d24fMaurice Lam        registerMixin(NavigationBarMixin.class, new NavigationBarMixin(this));
850ceb8d53e39ebb5bc103863787afb39ec5c41ad8Maurice Lam        final RequireScrollMixin requireScrollMixin = new RequireScrollMixin(this);
860ceb8d53e39ebb5bc103863787afb39ec5c41ad8Maurice Lam        registerMixin(RequireScrollMixin.class, requireScrollMixin);
870ceb8d53e39ebb5bc103863787afb39ec5c41ad8Maurice Lam
880ceb8d53e39ebb5bc103863787afb39ec5c41ad8Maurice Lam        final ScrollView scrollView = getScrollView();
890ceb8d53e39ebb5bc103863787afb39ec5c41ad8Maurice Lam        if (scrollView != null) {
900ceb8d53e39ebb5bc103863787afb39ec5c41ad8Maurice Lam            requireScrollMixin.setScrollHandlingDelegate(
910ceb8d53e39ebb5bc103863787afb39ec5c41ad8Maurice Lam                    new ScrollViewScrollHandlingDelegate(requireScrollMixin, scrollView));
920ceb8d53e39ebb5bc103863787afb39ec5c41ad8Maurice Lam        }
937514f1cee29b3feb4822ce16945c1c312057d24fMaurice Lam
949f9367672191190f903955d09a4314d40869acc6Maurice Lam        final TypedArray a = getContext().obtainStyledAttributes(attrs,
9595af12dac219e6945bab6142ea3a4099077314aaMaurice Lam                R.styleable.SuwSetupWizardLayout, defStyleAttr, 0);
9695af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
9795af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        // Set the background from XML, either directly or built from a bitmap tile
9895af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        final Drawable background =
9995af12dac219e6945bab6142ea3a4099077314aaMaurice Lam                a.getDrawable(R.styleable.SuwSetupWizardLayout_suwBackground);
10095af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        if (background != null) {
101b73a15f71e63dd46bf4dab94ca13caa861ac948fMaurice Lam            setLayoutBackground(background);
10295af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        } else {
10395af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            final Drawable backgroundTile =
10495af12dac219e6945bab6142ea3a4099077314aaMaurice Lam                    a.getDrawable(R.styleable.SuwSetupWizardLayout_suwBackgroundTile);
10595af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            if (backgroundTile != null) {
10695af12dac219e6945bab6142ea3a4099077314aaMaurice Lam                setBackgroundTile(backgroundTile);
10795af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            }
10895af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        }
10995af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
11095af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        // Set the illustration from XML, either directly or built from image + horizontal tile
11195af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        final Drawable illustration =
11295af12dac219e6945bab6142ea3a4099077314aaMaurice Lam                a.getDrawable(R.styleable.SuwSetupWizardLayout_suwIllustration);
11395af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        if (illustration != null) {
11495af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            setIllustration(illustration);
11595af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        } else {
11695af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            final Drawable illustrationImage =
11795af12dac219e6945bab6142ea3a4099077314aaMaurice Lam                    a.getDrawable(R.styleable.SuwSetupWizardLayout_suwIllustrationImage);
11895af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            final Drawable horizontalTile = a.getDrawable(
11995af12dac219e6945bab6142ea3a4099077314aaMaurice Lam                    R.styleable.SuwSetupWizardLayout_suwIllustrationHorizontalTile);
12095af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            if (illustrationImage != null && horizontalTile != null) {
12195af12dac219e6945bab6142ea3a4099077314aaMaurice Lam                setIllustration(illustrationImage, horizontalTile);
12295af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            }
12395af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        }
12495af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
1257114577a094593dbf55b625146b3809800697030Jorim Jaggi        // Set the top padding of the illustration
1267114577a094593dbf55b625146b3809800697030Jorim Jaggi        int decorPaddingTop = a.getDimensionPixelSize(
1277114577a094593dbf55b625146b3809800697030Jorim Jaggi                R.styleable.SuwSetupWizardLayout_suwDecorPaddingTop, -1);
1287114577a094593dbf55b625146b3809800697030Jorim Jaggi        if (decorPaddingTop == -1) {
1297114577a094593dbf55b625146b3809800697030Jorim Jaggi            decorPaddingTop = getResources().getDimensionPixelSize(R.dimen.suw_decor_padding_top);
1307114577a094593dbf55b625146b3809800697030Jorim Jaggi        }
1317114577a094593dbf55b625146b3809800697030Jorim Jaggi        setDecorPaddingTop(decorPaddingTop);
1327114577a094593dbf55b625146b3809800697030Jorim Jaggi
1337114577a094593dbf55b625146b3809800697030Jorim Jaggi
1347114577a094593dbf55b625146b3809800697030Jorim Jaggi        // Set the illustration aspect ratio. See Illustration.setAspectRatio(float). This will
13563cdc5ccb7f1f61d0e752e38d7e57c690658a0acMaurice Lam        // override suwDecorPaddingTop if its value is not 0.
1367114577a094593dbf55b625146b3809800697030Jorim Jaggi        float illustrationAspectRatio = a.getFloat(
1377114577a094593dbf55b625146b3809800697030Jorim Jaggi                R.styleable.SuwSetupWizardLayout_suwIllustrationAspectRatio, -1f);
1387114577a094593dbf55b625146b3809800697030Jorim Jaggi        if (illustrationAspectRatio == -1f) {
1397114577a094593dbf55b625146b3809800697030Jorim Jaggi            final TypedValue out = new TypedValue();
1407114577a094593dbf55b625146b3809800697030Jorim Jaggi            getResources().getValue(R.dimen.suw_illustration_aspect_ratio, out, true);
1417114577a094593dbf55b625146b3809800697030Jorim Jaggi            illustrationAspectRatio = out.getFloat();
1427114577a094593dbf55b625146b3809800697030Jorim Jaggi        }
1437114577a094593dbf55b625146b3809800697030Jorim Jaggi        setIllustrationAspectRatio(illustrationAspectRatio);
1447114577a094593dbf55b625146b3809800697030Jorim Jaggi
14595af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        a.recycle();
14695af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    }
14795af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
14895af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    @Override
149d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam    protected Parcelable onSaveInstanceState() {
150d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam        final Parcelable parcelable = super.onSaveInstanceState();
151d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam        final SavedState ss = new SavedState(parcelable);
1520e9b312956dd28cef21473337800919eb0a54b2dMaurice Lam        ss.mIsProgressBarShown = isProgressBarShown();
153d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam        return ss;
154d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam    }
155d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam
156d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam    @Override
157d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam    protected void onRestoreInstanceState(Parcelable state) {
1587f2a6e95f20408e055bb8b965b9e2bc664eec86bMaurice Lam        if (!(state instanceof SavedState)) {
1597f2a6e95f20408e055bb8b965b9e2bc664eec86bMaurice Lam            Log.w(TAG, "Ignoring restore instance state " + state);
1607f2a6e95f20408e055bb8b965b9e2bc664eec86bMaurice Lam            super.onRestoreInstanceState(state);
1617f2a6e95f20408e055bb8b965b9e2bc664eec86bMaurice Lam            return;
1627f2a6e95f20408e055bb8b965b9e2bc664eec86bMaurice Lam        }
1637f2a6e95f20408e055bb8b965b9e2bc664eec86bMaurice Lam
164d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam        final SavedState ss = (SavedState) state;
165d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam        super.onRestoreInstanceState(ss.getSuperState());
1660e9b312956dd28cef21473337800919eb0a54b2dMaurice Lam        final boolean isProgressBarShown = ss.mIsProgressBarShown;
1670ceb8d53e39ebb5bc103863787afb39ec5c41ad8Maurice Lam        setProgressBarShown(isProgressBarShown);
168d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam    }
169d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam
170d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam    @Override
17195af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    protected View onInflateTemplate(LayoutInflater inflater, int template) {
17295af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        if (template == 0) {
17395af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            template = R.layout.suw_template;
17495af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        }
175e2a8d27c2a43cf0b48b80e5b05f893222c541e04Maurice Lam        return inflateTemplate(inflater, R.style.SuwThemeMaterial_Light, template);
17695af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    }
17795af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
178bdfc0132ff90a333de202adfbf204cdc8139e632Maurice Lam    @Override
179bdfc0132ff90a333de202adfbf204cdc8139e632Maurice Lam    protected ViewGroup findContainer(int containerId) {
180bdfc0132ff90a333de202adfbf204cdc8139e632Maurice Lam        if (containerId == 0) {
181bdfc0132ff90a333de202adfbf204cdc8139e632Maurice Lam            containerId = R.id.suw_layout_content;
182bdfc0132ff90a333de202adfbf204cdc8139e632Maurice Lam        }
183bdfc0132ff90a333de202adfbf204cdc8139e632Maurice Lam        return super.findContainer(containerId);
18495af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    }
18595af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
1867e5f0f0ea3b3075258cac9d26f90fd97c1a71dcaMaurice Lam    public NavigationBar getNavigationBar() {
1877514f1cee29b3feb4822ce16945c1c312057d24fMaurice Lam        return getMixin(NavigationBarMixin.class).getNavigationBar();
1887e5f0f0ea3b3075258cac9d26f90fd97c1a71dcaMaurice Lam    }
1897e5f0f0ea3b3075258cac9d26f90fd97c1a71dcaMaurice Lam
19095abb283deb209532bbbae4ade3f5cc149a548a6Maurice Lam    public ScrollView getScrollView() {
191ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam        final View view = findManagedViewById(R.id.suw_bottom_scroll_view);
19295abb283deb209532bbbae4ade3f5cc149a548a6Maurice Lam        return view instanceof ScrollView ? (ScrollView) view : null;
1932d77e072fed129b34e473c7f77246a2b064fab7dMaurice Lam    }
1942d77e072fed129b34e473c7f77246a2b064fab7dMaurice Lam
1952d77e072fed129b34e473c7f77246a2b064fab7dMaurice Lam    public void requireScrollToBottom() {
1960ceb8d53e39ebb5bc103863787afb39ec5c41ad8Maurice Lam        final RequireScrollMixin requireScrollMixin = getMixin(RequireScrollMixin.class);
1972d77e072fed129b34e473c7f77246a2b064fab7dMaurice Lam        final NavigationBar navigationBar = getNavigationBar();
1980ceb8d53e39ebb5bc103863787afb39ec5c41ad8Maurice Lam        if (navigationBar != null) {
1990ceb8d53e39ebb5bc103863787afb39ec5c41ad8Maurice Lam            requireScrollMixin.requireScrollWithNavigationBar(navigationBar);
2002d77e072fed129b34e473c7f77246a2b064fab7dMaurice Lam        } else {
2010ceb8d53e39ebb5bc103863787afb39ec5c41ad8Maurice Lam            Log.e(TAG, "Cannot require scroll. Navigation bar is null.");
2022d77e072fed129b34e473c7f77246a2b064fab7dMaurice Lam        }
2032d77e072fed129b34e473c7f77246a2b064fab7dMaurice Lam    }
2042d77e072fed129b34e473c7f77246a2b064fab7dMaurice Lam
20595af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    public void setHeaderText(int title) {
2067514f1cee29b3feb4822ce16945c1c312057d24fMaurice Lam        getMixin(HeaderMixin.class).setText(title);
20795af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    }
20895af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
20995af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    public void setHeaderText(CharSequence title) {
2107514f1cee29b3feb4822ce16945c1c312057d24fMaurice Lam        getMixin(HeaderMixin.class).setText(title);
21195af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    }
21295af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
213caf3ce9f8da61e59a7b7dacbce2e1f8e23d3231eRussell Brenner    public CharSequence getHeaderText() {
2147514f1cee29b3feb4822ce16945c1c312057d24fMaurice Lam        return getMixin(HeaderMixin.class).getText();
215caf3ce9f8da61e59a7b7dacbce2e1f8e23d3231eRussell Brenner    }
216caf3ce9f8da61e59a7b7dacbce2e1f8e23d3231eRussell Brenner
2176cd984308b537924865bde77c2ee13d072cd9a48Udam Saini    public TextView getHeaderTextView() {
2187514f1cee29b3feb4822ce16945c1c312057d24fMaurice Lam        return getMixin(HeaderMixin.class).getTextView();
2196cd984308b537924865bde77c2ee13d072cd9a48Udam Saini    }
2206cd984308b537924865bde77c2ee13d072cd9a48Udam Saini
22195af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    /**
22295af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     * Set the illustration of the layout. The drawable will be applied as is, and the bounds will
22395af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     * be set as implemented in {@link com.android.setupwizardlib.view.Illustration}. To create
22495af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     * a suitable drawable from an asset and a horizontal repeating tile, use
22595af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     * {@link #setIllustration(int, int)} instead.
22695af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     *
22795af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     * @param drawable The drawable specifying the illustration.
22895af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     */
22995af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    public void setIllustration(Drawable drawable) {
230ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam        final View view = findManagedViewById(R.id.suw_layout_decor);
23195af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        if (view instanceof Illustration) {
23295af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            final Illustration illustration = (Illustration) view;
23395af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            illustration.setIllustration(drawable);
23495af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        }
23595af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    }
23695af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
23795af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    /**
23895af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     * Set the illustration of the layout, which will be created asset and the horizontal tile as
23995af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     * suitable. On phone layouts (not sw600dp), the asset will be scaled, maintaining aspect ratio.
24095af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     * On tablets (sw600dp), the assets will always have 256dp height and the rest of the
24195af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     * illustration area that the asset doesn't fill will be covered by the horizontalTile.
24295af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     *
24395af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     * @param asset Resource ID of the illustration asset.
24495af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     * @param horizontalTile Resource ID of the horizontally repeating tile for tablet layout.
24595af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     */
24695af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    public void setIllustration(int asset, int horizontalTile) {
247ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam        final View view = findManagedViewById(R.id.suw_layout_decor);
24895af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        if (view instanceof Illustration) {
24995af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            final Illustration illustration = (Illustration) view;
25095af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            final Drawable illustrationDrawable = getIllustration(asset, horizontalTile);
25195af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            illustration.setIllustration(illustrationDrawable);
25295af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        }
25395af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    }
25495af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
25595af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    private void setIllustration(Drawable asset, Drawable horizontalTile) {
256ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam        final View view = findManagedViewById(R.id.suw_layout_decor);
25795af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        if (view instanceof Illustration) {
25895af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            final Illustration illustration = (Illustration) view;
25995af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            final Drawable illustrationDrawable = getIllustration(asset, horizontalTile);
26095af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            illustration.setIllustration(illustrationDrawable);
26195af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        }
26295af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    }
26395af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
26495af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    /**
2657114577a094593dbf55b625146b3809800697030Jorim Jaggi     * Sets the aspect ratio of the illustration. This will be the space (padding top) reserved
2667114577a094593dbf55b625146b3809800697030Jorim Jaggi     * above the header text. This will override the padding top of the illustration.
2677114577a094593dbf55b625146b3809800697030Jorim Jaggi     *
2687114577a094593dbf55b625146b3809800697030Jorim Jaggi     * @param aspectRatio The aspect ratio
2697114577a094593dbf55b625146b3809800697030Jorim Jaggi     * @see com.android.setupwizardlib.view.Illustration#setAspectRatio(float)
2707114577a094593dbf55b625146b3809800697030Jorim Jaggi     */
2717114577a094593dbf55b625146b3809800697030Jorim Jaggi    public void setIllustrationAspectRatio(float aspectRatio) {
272ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam        final View view = findManagedViewById(R.id.suw_layout_decor);
2737114577a094593dbf55b625146b3809800697030Jorim Jaggi        if (view instanceof Illustration) {
2747114577a094593dbf55b625146b3809800697030Jorim Jaggi            final Illustration illustration = (Illustration) view;
2757114577a094593dbf55b625146b3809800697030Jorim Jaggi            illustration.setAspectRatio(aspectRatio);
2767114577a094593dbf55b625146b3809800697030Jorim Jaggi        }
2777114577a094593dbf55b625146b3809800697030Jorim Jaggi    }
2787114577a094593dbf55b625146b3809800697030Jorim Jaggi
2797114577a094593dbf55b625146b3809800697030Jorim Jaggi    /**
2807114577a094593dbf55b625146b3809800697030Jorim Jaggi     * Set the top padding of the decor view. If the decor is an Illustration and the aspect ratio
2817114577a094593dbf55b625146b3809800697030Jorim Jaggi     * is set, this value will be overridden.
2827114577a094593dbf55b625146b3809800697030Jorim Jaggi     *
283b38561602db3fc1b31c7ee907da41ec2c53e4764Maurice Lam     * <p>Note: Currently the default top padding for tablet landscape is 128dp, which is the offset
2847114577a094593dbf55b625146b3809800697030Jorim Jaggi     * of the card from the top. This is likely to change in future versions so this value aligns
2857114577a094593dbf55b625146b3809800697030Jorim Jaggi     * with the height of the illustration instead.
2867114577a094593dbf55b625146b3809800697030Jorim Jaggi     *
2877114577a094593dbf55b625146b3809800697030Jorim Jaggi     * @param paddingTop The top padding in pixels.
2887114577a094593dbf55b625146b3809800697030Jorim Jaggi     */
2897114577a094593dbf55b625146b3809800697030Jorim Jaggi    public void setDecorPaddingTop(int paddingTop) {
290ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam        final View view = findManagedViewById(R.id.suw_layout_decor);
2917114577a094593dbf55b625146b3809800697030Jorim Jaggi        if (view != null) {
2927114577a094593dbf55b625146b3809800697030Jorim Jaggi            view.setPadding(view.getPaddingLeft(), paddingTop, view.getPaddingRight(),
2937114577a094593dbf55b625146b3809800697030Jorim Jaggi                    view.getPaddingBottom());
2947114577a094593dbf55b625146b3809800697030Jorim Jaggi        }
2957114577a094593dbf55b625146b3809800697030Jorim Jaggi    }
2967114577a094593dbf55b625146b3809800697030Jorim Jaggi
2977114577a094593dbf55b625146b3809800697030Jorim Jaggi    /**
29895af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     * Set the background of the layout, which is expected to be able to extend infinitely. If it is
29995af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     * a bitmap tile and you want it to repeat, use {@link #setBackgroundTile(int)} instead.
30095af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     */
301b73a15f71e63dd46bf4dab94ca13caa861ac948fMaurice Lam    public void setLayoutBackground(Drawable background) {
302ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam        final View view = findManagedViewById(R.id.suw_layout_decor);
30395af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        if (view != null) {
304b8f3330e8be7da2f141b65967ecf3a2bad4e02a4Maurice Lam            //noinspection deprecation
305b8f3330e8be7da2f141b65967ecf3a2bad4e02a4Maurice Lam            view.setBackgroundDrawable(background);
30695af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        }
30795af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    }
30895af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
30995af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    /**
31095af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     * Set the background of the layout to a repeating bitmap tile. To use a different kind of
311b73a15f71e63dd46bf4dab94ca13caa861ac948fMaurice Lam     * drawable, use {@link #setLayoutBackground(android.graphics.drawable.Drawable)} instead.
31295af12dac219e6945bab6142ea3a4099077314aaMaurice Lam     */
31395af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    public void setBackgroundTile(int backgroundTile) {
314b8f3330e8be7da2f141b65967ecf3a2bad4e02a4Maurice Lam        final Drawable backgroundTileDrawable =
315b8f3330e8be7da2f141b65967ecf3a2bad4e02a4Maurice Lam                getContext().getResources().getDrawable(backgroundTile);
31695af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        setBackgroundTile(backgroundTileDrawable);
31795af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    }
31895af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
31995af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    private void setBackgroundTile(Drawable backgroundTile) {
32095af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        if (backgroundTile instanceof BitmapDrawable) {
32195af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            ((BitmapDrawable) backgroundTile).setTileModeXY(TileMode.REPEAT, TileMode.REPEAT);
32295af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        }
323b73a15f71e63dd46bf4dab94ca13caa861ac948fMaurice Lam        setLayoutBackground(backgroundTile);
32495af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    }
32595af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
32695af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    private Drawable getIllustration(int asset, int horizontalTile) {
32795af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        final Context context = getContext();
32895af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        final Drawable assetDrawable = context.getResources().getDrawable(asset);
32995af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        final Drawable tile = context.getResources().getDrawable(horizontalTile);
33095af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        return getIllustration(assetDrawable, tile);
33195af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    }
33295af12dac219e6945bab6142ea3a4099077314aaMaurice Lam
33395af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    @SuppressLint("RtlHardcoded")
33495af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    private Drawable getIllustration(Drawable asset, Drawable horizontalTile) {
33595af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        final Context context = getContext();
33695af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        if (context.getResources().getBoolean(R.bool.suwUseTabletLayout)) {
33795af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            // If it is a "tablet" (sw600dp), create a LayerDrawable with the horizontal tile.
33895af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            if (horizontalTile instanceof BitmapDrawable) {
33995af12dac219e6945bab6142ea3a4099077314aaMaurice Lam                ((BitmapDrawable) horizontalTile).setTileModeX(TileMode.REPEAT);
34095af12dac219e6945bab6142ea3a4099077314aaMaurice Lam                ((BitmapDrawable) horizontalTile).setGravity(Gravity.TOP);
34195af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            }
34295af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            if (asset instanceof BitmapDrawable) {
34395af12dac219e6945bab6142ea3a4099077314aaMaurice Lam                // Always specify TOP | LEFT, Illustration will flip the entire LayerDrawable.
34495af12dac219e6945bab6142ea3a4099077314aaMaurice Lam                ((BitmapDrawable) asset).setGravity(Gravity.TOP | Gravity.LEFT);
34595af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            }
34695af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            final LayerDrawable layers =
34795af12dac219e6945bab6142ea3a4099077314aaMaurice Lam                    new LayerDrawable(new Drawable[] { horizontalTile, asset });
348b8f3330e8be7da2f141b65967ecf3a2bad4e02a4Maurice Lam            if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
349b8f3330e8be7da2f141b65967ecf3a2bad4e02a4Maurice Lam                layers.setAutoMirrored(true);
350b8f3330e8be7da2f141b65967ecf3a2bad4e02a4Maurice Lam            }
35195af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            return layers;
35295af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        } else {
35395af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            // If it is a "phone" (not sw600dp), simply return the illustration
354b8f3330e8be7da2f141b65967ecf3a2bad4e02a4Maurice Lam            if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
355b8f3330e8be7da2f141b65967ecf3a2bad4e02a4Maurice Lam                asset.setAutoMirrored(true);
356b8f3330e8be7da2f141b65967ecf3a2bad4e02a4Maurice Lam            }
35795af12dac219e6945bab6142ea3a4099077314aaMaurice Lam            return asset;
35895af12dac219e6945bab6142ea3a4099077314aaMaurice Lam        }
35995af12dac219e6945bab6142ea3a4099077314aaMaurice Lam    }
360d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam
361d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam    public boolean isProgressBarShown() {
3627514f1cee29b3feb4822ce16945c1c312057d24fMaurice Lam        return getMixin(ProgressBarMixin.class).isShown();
363d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam    }
364d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam
365ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam    /**
366ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam     * Sets whether the progress bar below the header text is shown or not. The progress bar is
367ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam     * a lazily inflated ViewStub, which means the progress bar will not actually be part of the
368ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam     * view hierarchy until the first time this is set to {@code true}.
369ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam     */
370ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam    public void setProgressBarShown(boolean shown) {
3717514f1cee29b3feb4822ce16945c1c312057d24fMaurice Lam        getMixin(ProgressBarMixin.class).setShown(shown);
372d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam    }
373d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam
374ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam    /**
375ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam     * @deprecated Use {@link #setProgressBarShown(boolean)}
376ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam     */
377ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam    @Deprecated
378ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam    public void showProgressBar() {
379ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam        setProgressBarShown(true);
380ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam    }
381ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam
382ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam    /**
383ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam     * @deprecated Use {@link #setProgressBarShown(boolean)}
384ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam     */
385ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam    @Deprecated
386d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam    public void hideProgressBar() {
387ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam        setProgressBarShown(false);
388d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam    }
389d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam
390bf4afac02228e42af171bbb5f3db11977be487b1Maurice Lam    public void setProgressBarColor(ColorStateList color) {
3917514f1cee29b3feb4822ce16945c1c312057d24fMaurice Lam        getMixin(ProgressBarMixin.class).setColor(color);
392bf4afac02228e42af171bbb5f3db11977be487b1Maurice Lam    }
393bf4afac02228e42af171bbb5f3db11977be487b1Maurice Lam
394bf4afac02228e42af171bbb5f3db11977be487b1Maurice Lam    public ColorStateList getProgressBarColor() {
3957514f1cee29b3feb4822ce16945c1c312057d24fMaurice Lam        return getMixin(ProgressBarMixin.class).getColor();
396bf4afac02228e42af171bbb5f3db11977be487b1Maurice Lam    }
397bf4afac02228e42af171bbb5f3db11977be487b1Maurice Lam
3988c10c403c063aff3f17c4949b0fe9a88536ae580Maurice Lam    /* Misc */
3998c10c403c063aff3f17c4949b0fe9a88536ae580Maurice Lam
400d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam    protected static class SavedState extends BaseSavedState {
401d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam
4020e9b312956dd28cef21473337800919eb0a54b2dMaurice Lam        boolean mIsProgressBarShown = false;
403d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam
404d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam        public SavedState(Parcelable parcelable) {
405d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam            super(parcelable);
406d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam        }
407d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam
408d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam        public SavedState(Parcel source) {
409d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam            super(source);
4100e9b312956dd28cef21473337800919eb0a54b2dMaurice Lam            mIsProgressBarShown = source.readInt() != 0;
411d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam        }
412d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam
413d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam        @Override
414d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam        public void writeToParcel(Parcel dest, int flags) {
415d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam            super.writeToParcel(dest, flags);
4160e9b312956dd28cef21473337800919eb0a54b2dMaurice Lam            dest.writeInt(mIsProgressBarShown ? 1 : 0);
417d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam        }
418d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam
419d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam        public static final Parcelable.Creator<SavedState> CREATOR =
420d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam                new Parcelable.Creator<SavedState>() {
421d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam
422d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam                    @Override
423d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam                    public SavedState createFromParcel(Parcel parcel) {
424d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam                        return new SavedState(parcel);
425d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam                    }
426d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam
427d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam                    @Override
428d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam                    public SavedState[] newArray(int size) {
429d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam                        return new SavedState[size];
430d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam                    }
431d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam                };
432d61674efcfaa9f591a44fc75d59566cdd5b409ebMaurice Lam    }
433d4c6ef70612f48c4612ec827bd89964d0955cd6fMaurice Lam}
434