1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.setupwizardlib;
18
19import android.annotation.TargetApi;
20import android.content.Context;
21import android.content.res.ColorStateList;
22import android.content.res.TypedArray;
23import android.graphics.drawable.Drawable;
24import android.os.Build;
25import android.os.Build.VERSION_CODES;
26import android.util.AttributeSet;
27import android.view.InflateException;
28import android.view.LayoutInflater;
29import android.view.View;
30import android.view.ViewGroup;
31import android.view.ViewStub;
32import android.widget.ImageView;
33import android.widget.ProgressBar;
34import android.widget.ScrollView;
35import android.widget.TextView;
36
37import com.android.setupwizardlib.view.StatusBarBackgroundLayout;
38
39/**
40 * Layout for the GLIF theme used in Setup Wizard for N.
41 *
42 * <p>Example usage:
43 * <pre>{@code
44 * &lt;com.android.setupwizardlib.GlifLayout
45 *     xmlns:android="http://schemas.android.com/apk/res/android"
46 *     xmlns:app="http://schemas.android.com/apk/res-auto"
47 *     android:layout_width="match_parent"
48 *     android:layout_height="match_parent"
49 *     android:icon="@drawable/my_icon"
50 *     app:suwHeaderText="@string/my_title">
51 *
52 *     &lt;!-- Content here -->
53 *
54 * &lt;/com.android.setupwizardlib.GlifLayout>
55 * }</pre>
56 */
57public class GlifLayout extends TemplateLayout {
58
59    private static final String TAG = "GlifLayout";
60
61    private ColorStateList mPrimaryColor;
62
63    public GlifLayout(Context context) {
64        this(context, 0, 0);
65    }
66
67    public GlifLayout(Context context, int template) {
68        this(context, template, 0);
69    }
70
71    public GlifLayout(Context context, int template, int containerId) {
72        super(context, template, containerId);
73        init(null, R.attr.suwLayoutTheme);
74    }
75
76    public GlifLayout(Context context, AttributeSet attrs) {
77        super(context, attrs);
78        init(attrs, R.attr.suwLayoutTheme);
79    }
80
81    @TargetApi(VERSION_CODES.HONEYCOMB)
82    public GlifLayout(Context context, AttributeSet attrs, int defStyleAttr) {
83        super(context, attrs, defStyleAttr);
84        init(attrs, defStyleAttr);
85    }
86
87    // All the constructors delegate to this init method. The 3-argument constructor is not
88    // available in LinearLayout before v11, so call super with the exact same arguments.
89    private void init(AttributeSet attrs, int defStyleAttr) {
90        final TypedArray a = getContext().obtainStyledAttributes(attrs,
91                R.styleable.SuwGlifLayout, defStyleAttr, 0);
92
93        final Drawable icon = a.getDrawable(R.styleable.SuwGlifLayout_android_icon);
94        if (icon != null) {
95            setIcon(icon);
96        }
97
98        // Set the header color
99        final ColorStateList headerColor =
100                a.getColorStateList(R.styleable.SuwGlifLayout_suwHeaderColor);
101        if (headerColor != null) {
102            setHeaderColor(headerColor);
103        }
104
105
106        // Set the header text
107        final CharSequence headerText =
108                a.getText(R.styleable.SuwGlifLayout_suwHeaderText);
109        if (headerText != null) {
110            setHeaderText(headerText);
111        }
112
113        final ColorStateList primaryColor =
114                a.getColorStateList(R.styleable.SuwGlifLayout_android_colorPrimary);
115        setPrimaryColor(primaryColor);
116
117        a.recycle();
118    }
119
120    @Override
121    protected View onInflateTemplate(LayoutInflater inflater, int template) {
122        if (template == 0) {
123            template = R.layout.suw_glif_template;
124        }
125        try {
126            return super.onInflateTemplate(inflater, template);
127        } catch (RuntimeException e) {
128            // Versions before M throws RuntimeException for unsuccessful attribute resolution
129            // Versions M+ will throw an InflateException (which extends from RuntimeException)
130            throw new InflateException("Unable to inflate layout. Are you using "
131                    + "@style/SuwThemeGlif (or its descendant) as your theme?", e);
132        }
133    }
134
135    @Override
136    protected ViewGroup findContainer(int containerId) {
137        if (containerId == 0) {
138            containerId = R.id.suw_layout_content;
139        }
140        return super.findContainer(containerId);
141    }
142
143    /**
144     * Same as {@link android.view.View#findViewById(int)}, but may include views that are managed
145     * by this view but not currently added to the view hierarchy. e.g. recycler view or list view
146     * headers that are not currently shown.
147     */
148    protected View findManagedViewById(int id) {
149        return findViewById(id);
150    }
151
152    public ScrollView getScrollView() {
153        final View view = findManagedViewById(R.id.suw_scroll_view);
154        return view instanceof ScrollView ? (ScrollView) view : null;
155    }
156
157    public TextView getHeaderTextView() {
158        return (TextView) findManagedViewById(R.id.suw_layout_title);
159    }
160
161    public void setHeaderText(int title) {
162        setHeaderText(getContext().getResources().getText(title));
163    }
164
165    public void setHeaderText(CharSequence title) {
166        final TextView titleView = getHeaderTextView();
167        if (titleView != null) {
168            titleView.setText(title);
169        }
170    }
171
172    public CharSequence getHeaderText() {
173        final TextView titleView = getHeaderTextView();
174        return titleView != null ? titleView.getText() : null;
175    }
176
177    public void setHeaderColor(ColorStateList color) {
178        final TextView titleView = getHeaderTextView();
179        if (titleView != null) {
180            titleView.setTextColor(color);
181        }
182    }
183
184    public ColorStateList getHeaderColor() {
185        final TextView titleView = getHeaderTextView();
186        return titleView != null ? titleView.getTextColors() : null;
187    }
188
189    public void setIcon(Drawable icon) {
190        final ImageView iconView = getIconView();
191        if (iconView != null) {
192            iconView.setImageDrawable(icon);
193        }
194    }
195
196    public Drawable getIcon() {
197        final ImageView iconView = getIconView();
198        return iconView != null ? iconView.getDrawable() : null;
199    }
200
201    protected ImageView getIconView() {
202        return (ImageView) findManagedViewById(R.id.suw_layout_icon);
203    }
204
205    public void setPrimaryColor(ColorStateList color) {
206        mPrimaryColor = color;
207        setGlifPatternColor(color);
208        setProgressBarColor(color);
209    }
210
211    public ColorStateList getPrimaryColor() {
212        return mPrimaryColor;
213    }
214
215    private void setGlifPatternColor(ColorStateList color) {
216        if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
217            setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
218            final View patternBg = findManagedViewById(R.id.suw_pattern_bg);
219            if (patternBg != null) {
220                final GlifPatternDrawable background =
221                        new GlifPatternDrawable(color.getDefaultColor());
222                if (patternBg instanceof StatusBarBackgroundLayout) {
223                    ((StatusBarBackgroundLayout) patternBg).setStatusBarBackground(background);
224                } else {
225                    patternBg.setBackground(background);
226                }
227            }
228        }
229    }
230
231    public boolean isProgressBarShown() {
232        final View progressBar = findManagedViewById(R.id.suw_layout_progress);
233        return progressBar != null && progressBar.getVisibility() == View.VISIBLE;
234    }
235
236    public void setProgressBarShown(boolean shown) {
237        final View progressBar = findManagedViewById(R.id.suw_layout_progress);
238        if (shown) {
239            if (progressBar != null) {
240                progressBar.setVisibility(View.VISIBLE);
241            } else {
242                final ViewStub progressBarStub =
243                        (ViewStub) findManagedViewById(R.id.suw_layout_progress_stub);
244                if (progressBarStub != null) {
245                    progressBarStub.inflate();
246                }
247            }
248            setProgressBarColor(mPrimaryColor);
249        } else {
250            if (progressBar != null) {
251                progressBar.setVisibility(View.GONE);
252            }
253        }
254    }
255
256    private void setProgressBarColor(ColorStateList color) {
257        if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
258            final ProgressBar bar = (ProgressBar) findManagedViewById(R.id.suw_layout_progress);
259            if (bar != null) {
260                bar.setIndeterminateTintList(color);
261            }
262        }
263    }
264}
265