• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 package com.android.car.setupwizardlib;
17 
18 import android.content.Context;
19 import android.content.res.TypedArray;
20 import android.graphics.PorterDuff;
21 import android.graphics.Rect;
22 import android.graphics.Typeface;
23 import android.graphics.drawable.Drawable;
24 import android.graphics.drawable.GradientDrawable;
25 import android.graphics.drawable.InsetDrawable;
26 import android.graphics.drawable.RippleDrawable;
27 import android.text.TextUtils;
28 import android.util.AttributeSet;
29 import android.util.Log;
30 import android.util.TypedValue;
31 import android.view.LayoutInflater;
32 import android.view.TouchDelegate;
33 import android.view.View;
34 import android.view.ViewGroup;
35 import android.view.ViewStub;
36 import android.widget.Button;
37 import android.widget.ImageView;
38 import android.widget.LinearLayout;
39 import android.widget.ProgressBar;
40 import android.widget.TextView;
41 import androidx.annotation.Nullable;
42 import androidx.annotation.StyleRes;
43 import androidx.annotation.VisibleForTesting;
44 import com.android.car.setupwizardlib.partner.PartnerConfig;
45 import com.android.car.setupwizardlib.partner.PartnerConfigHelper;
46 import java.util.Locale;
47 import java.util.Objects;
48 
49 /**
50  * Custom layout for the Car Setup Wizard. Provides accessors for modifying elements such as buttons
51  * and progress bars. Any modifications to elements built by
52  * the CarSetupWizardLayout should be done through methods provided by this class unless that is
53  * not possible so as to keep the state internally consistent.
54  *
55  * @deprecated Use {@link CarSetupWizardCompatLayout} or {@link CarSetupWizardDesignLayout}.
56  */
57 @Deprecated
58 public class CarSetupWizardLayout extends LinearLayout {
59     private static final String TAG = CarSetupWizardLayout.class.getSimpleName();
60 
61     private View mBackButton;
62     private View mTitleBar;
63     private TextView mToolbarTitle;
64     private PartnerConfigHelper mPartnerConfigHelper;
65 
66     /* <p>The Primary Toolbar Button should always be used when there is only a single action that
67      * moves the wizard to the next screen (e.g. Only need a 'Skip' button).
68      *
69      * When there are two actions that can move the wizard to the next screen (e.g. either 'Skip'
70      * or 'Let's Go' are the two options), then the Primary is used for the positive action
71      * while the Secondary is used for the negative action.</p>
72      */
73     private Button mPrimaryToolbarButton;
74 
75     /*
76      * Flag to track the primary toolbar button flat state.
77      */
78     private boolean mPrimaryToolbarButtonFlat;
79     private View.OnClickListener mPrimaryToolbarButtonOnClick;
80     private Button mSecondaryToolbarButton;
81     private ProgressBar mProgressBar;
82 
CarSetupWizardLayout(Context context)83     public CarSetupWizardLayout(Context context) {
84         this(context, null);
85     }
86 
CarSetupWizardLayout(Context context, @Nullable AttributeSet attrs)87     public CarSetupWizardLayout(Context context, @Nullable AttributeSet attrs) {
88         this(context, attrs, 0);
89     }
90 
CarSetupWizardLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr)91     public CarSetupWizardLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
92         this(context, attrs, defStyleAttr, 0);
93     }
94 
95     /**
96      * On initialization, the layout gets all of the custom attributes and initializes
97      * the custom views that can be set by the user (e.g. back button, continue button).
98      */
CarSetupWizardLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)99     public CarSetupWizardLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
100             int defStyleRes) {
101         super(context, attrs, defStyleAttr, defStyleRes);
102 
103         mPartnerConfigHelper = PartnerConfigHelper.get(context);
104         TypedArray attrArray = context.getTheme().obtainStyledAttributes(
105                 attrs,
106                 R.styleable.CarSetupWizardLayout,
107                 0, 0);
108 
109         init(attrArray);
110     }
111 
112     /**
113      * Inflates the layout and sets the custom views (e.g. back button, continue button).
114      */
init(TypedArray attrArray)115     private void init(TypedArray attrArray) {
116         boolean showBackButton;
117 
118         boolean showToolbarTitle;
119         String toolbarTitleText;
120 
121         boolean showPrimaryToolbarButton;
122         String primaryToolbarButtonText;
123         boolean primaryToolbarButtonEnabled;
124 
125         boolean showSecondaryToolbarButton;
126         String secondaryToolbarButtonText;
127         boolean secondaryToolbarButtonEnabled;
128 
129         boolean showProgressBar;
130         boolean indeterminateProgressBar;
131 
132         try {
133             showBackButton = attrArray.getBoolean(
134                     R.styleable.CarSetupWizardLayout_showBackButton, true);
135             showToolbarTitle = attrArray.getBoolean(
136                     R.styleable.CarSetupWizardLayout_showToolbarTitle, false);
137             toolbarTitleText = attrArray.getString(
138                     R.styleable.CarSetupWizardLayout_toolbarTitleText);
139             showPrimaryToolbarButton = attrArray.getBoolean(
140                     R.styleable.CarSetupWizardLayout_showPrimaryToolbarButton, true);
141             primaryToolbarButtonText = attrArray.getString(
142                     R.styleable.CarSetupWizardLayout_primaryToolbarButtonText);
143             primaryToolbarButtonEnabled = attrArray.getBoolean(
144                     R.styleable.CarSetupWizardLayout_primaryToolbarButtonEnabled, true);
145             mPrimaryToolbarButtonFlat = attrArray.getBoolean(
146                     R.styleable.CarSetupWizardLayout_primaryToolbarButtonFlat, false);
147             showSecondaryToolbarButton = attrArray.getBoolean(
148                     R.styleable.CarSetupWizardLayout_showSecondaryToolbarButton, false);
149             secondaryToolbarButtonText = attrArray.getString(
150                     R.styleable.CarSetupWizardLayout_secondaryToolbarButtonText);
151             secondaryToolbarButtonEnabled = attrArray.getBoolean(
152                     R.styleable.CarSetupWizardLayout_secondaryToolbarButtonEnabled, true);
153             showProgressBar = attrArray.getBoolean(
154                     R.styleable.CarSetupWizardLayout_showProgressBar, false);
155             indeterminateProgressBar = attrArray.getBoolean(
156                     R.styleable.CarSetupWizardLayout_indeterminateProgressBar, true);
157         } finally {
158             attrArray.recycle();
159         }
160 
161         LayoutInflater inflater = LayoutInflater.from(getContext());
162         inflater.inflate(R.layout.car_setup_wizard_layout, this);
163 
164         // Set the back button visibility based on the custom attribute.
165         setBackButton(findViewById(R.id.back_button));
166         Drawable drawable = mPartnerConfigHelper.getDrawable(
167                 getContext(), PartnerConfig.CONFIG_TOOLBAR_BUTTON_ICON_BACK);
168         if (drawable != null) {
169             ((ImageView) mBackButton).setImageDrawable(drawable);
170         }
171         setBackButtonVisible(showBackButton);
172 
173         // Se the title bar.
174         setTitleBar(findViewById(R.id.application_bar));
175         int toolbarBgColor =
176                 mPartnerConfigHelper.getColor(getContext(), PartnerConfig.CONFIG_TOOLBAR_BG_COLOR);
177         if (toolbarBgColor != 0) {
178             mTitleBar.setBackgroundColor(toolbarBgColor);
179         }
180 
181         // Set the toolbar title visibility and text based on the custom attributes.
182         setToolbarTitle(findViewById(R.id.toolbar_title));
183         if (showToolbarTitle) {
184             setToolbarTitleText(toolbarTitleText);
185         } else {
186             setToolbarTitleVisible(false);
187         }
188 
189         // Set the primary continue button visibility and text based on the custom attributes.
190         ViewStub primaryToolbarButtonStub =
191                 (ViewStub) findViewById(R.id.primary_toolbar_button_stub);
192         // Set the button layout to flat if that attribute was set.
193         if (mPrimaryToolbarButtonFlat) {
194             primaryToolbarButtonStub.setLayoutResource(R.layout.flat_button);
195         }
196         primaryToolbarButtonStub.inflate();
197         setPrimaryToolbarButton(findViewById(R.id.primary_toolbar_button));
198         if (showPrimaryToolbarButton) {
199             setPrimaryToolbarButtonText(primaryToolbarButtonText);
200             setPrimaryToolbarButtonEnabled(primaryToolbarButtonEnabled);
201 
202             setBackground(
203                     mPrimaryToolbarButton,
204                     PartnerConfig.CONFIG_TOOLBAR_PRIMARY_BUTTON_BG,
205                     PartnerConfig.CONFIG_TOOLBAR_PRIMARY_BUTTON_BG_COLOR);
206 
207             setButtonPadding(mPrimaryToolbarButton);
208             setButtonTypeFace(mPrimaryToolbarButton);
209             setButtonTextSize(mPrimaryToolbarButton);
210             setButtonTextColor(
211                     mPrimaryToolbarButton,
212                     PartnerConfig.CONFIG_TOOLBAR_PRIMARY_BUTTON_TEXT_COLOR);
213         } else {
214             setPrimaryToolbarButtonVisible(false);
215         }
216 
217         // Set the secondary continue button visibility and text based on the custom attributes.
218         ViewStub secondaryToolbarButtonStub =
219                 (ViewStub) findViewById(R.id.secondary_toolbar_button_stub);
220         if (showSecondaryToolbarButton || !TextUtils.isEmpty(secondaryToolbarButtonText)) {
221             secondaryToolbarButtonStub.inflate();
222             mSecondaryToolbarButton = findViewById(R.id.secondary_toolbar_button);
223             setSecondaryToolbarButtonText(secondaryToolbarButtonText);
224             setSecondaryToolbarButtonEnabled(secondaryToolbarButtonEnabled);
225             setSecondaryToolbarButtonVisible(showSecondaryToolbarButton);
226         }
227 
228         mProgressBar = findViewById(R.id.progress_bar);
229         setProgressBarVisible(showProgressBar);
230         setProgressBarIndeterminate(indeterminateProgressBar);
231 
232         // Set orientation programmatically since the inflated layout uses <merge>
233         setOrientation(LinearLayout.VERTICAL);
234     }
235 
236     /**
237      * Set a given view's visibility.
238      */
239     @VisibleForTesting
setViewVisible(View view, boolean visible)240     void setViewVisible(View view, boolean visible) {
241         view.setVisibility(visible ? View.VISIBLE : View.GONE);
242     }
243 
244     // Add or remove the back button touch delegate depending on whether it is visible.
245     @VisibleForTesting
updateBackButtonTouchDelegate(boolean visible)246     void updateBackButtonTouchDelegate(boolean visible) {
247         if (visible) {
248             // Post this action in the parent's message queue to make sure the parent
249             // lays out its children before getHitRect() is called
250             this.post(() -> {
251                 Rect delegateArea = new Rect();
252 
253                 mBackButton.getHitRect(delegateArea);
254 
255                 /*
256                  * Update the delegate area based on the difference between the current size and
257                  * the touch target size
258                  */
259                 float touchTargetSize = getResources().getDimension(
260                         R.dimen.car_touch_target_size);
261                 float primaryIconSize = getResources().getDimension(
262                         R.dimen.car_primary_icon_size);
263 
264                 int sizeDifference = (int) ((touchTargetSize - primaryIconSize) / 2);
265 
266                 delegateArea.right += sizeDifference;
267                 delegateArea.bottom += sizeDifference;
268                 delegateArea.left -= sizeDifference;
269                 delegateArea.top -= sizeDifference;
270 
271                 // Set the TouchDelegate on the parent view
272                 TouchDelegate touchDelegate = new TouchDelegate(delegateArea,
273                         mBackButton);
274 
275                 if (View.class.isInstance(mBackButton.getParent())) {
276                     ((View) mBackButton.getParent()).setTouchDelegate(touchDelegate);
277                 }
278             });
279         } else {
280             // Set the TouchDelegate to null if the back button is not visible.
281             if (View.class.isInstance(mBackButton.getParent())) {
282                 ((View) mBackButton.getParent()).setTouchDelegate(null);
283             }
284         }
285     }
286 
287     /**
288      * Gets the back button.
289      */
getBackButton()290     public View getBackButton() {
291         return mBackButton;
292     }
293 
294     @VisibleForTesting
setBackButton(View backButton)295     final void setBackButton(View backButton) {
296         mBackButton = backButton;
297     }
298 
299     /**
300      * Set the back button onClickListener to given listener. Can be null if the listener should
301      * be overridden so no callback is made.
302      */
setBackButtonListener(@ullable View.OnClickListener listener)303     public void setBackButtonListener(@Nullable View.OnClickListener listener) {
304         mBackButton.setOnClickListener(listener);
305     }
306 
307     /**
308      * Set the back button visibility to the given visibility.
309      */
setBackButtonVisible(boolean visible)310     public void setBackButtonVisible(boolean visible) {
311         setViewVisible(mBackButton, visible);
312         updateBackButtonTouchDelegate(visible);
313     }
314 
315     /**
316      * Gets the toolbar title.
317      */
getToolbarTitle()318     public TextView getToolbarTitle() {
319         return mToolbarTitle;
320     }
321 
322     @VisibleForTesting
setToolbarTitle(TextView toolbarTitle)323     final void setToolbarTitle(TextView toolbarTitle) {
324         mToolbarTitle = toolbarTitle;
325     }
326 
327     /**
328      * Sets the header title visibility to given value.
329      */
setToolbarTitleVisible(boolean visible)330     public void setToolbarTitleVisible(boolean visible) {
331         setViewVisible(mToolbarTitle, visible);
332     }
333 
334     /**
335      * Sets the header title text to the provided text.
336      */
setToolbarTitleText(String text)337     public void setToolbarTitleText(String text) {
338         mToolbarTitle.setText(text);
339     }
340 
341     /**
342      * Sets the style for the toolbar title.
343      */
setToolbarTitleStyle(@tyleRes int style)344     public void setToolbarTitleStyle(@StyleRes int style) {
345         mToolbarTitle.setTextAppearance(style);
346     }
347 
348     /**
349      * Gets the primary toolbar button.
350      */
getPrimaryToolbarButton()351     public Button getPrimaryToolbarButton() {
352         return mPrimaryToolbarButton;
353     }
354 
355     @VisibleForTesting
setPrimaryToolbarButton(Button primaryToolbarButton)356     final void setPrimaryToolbarButton(Button primaryToolbarButton) {
357         mPrimaryToolbarButton = primaryToolbarButton;
358     }
359 
360     /**
361      * Set the primary continue button visibility to the given visibility.
362      */
setPrimaryToolbarButtonVisible(boolean visible)363     public void setPrimaryToolbarButtonVisible(boolean visible) {
364         setViewVisible(mPrimaryToolbarButton, visible);
365     }
366 
367     /**
368      * Set whether the primary continue button is enabled.
369      */
setPrimaryToolbarButtonEnabled(boolean enabled)370     public void setPrimaryToolbarButtonEnabled(boolean enabled) {
371         mPrimaryToolbarButton.setEnabled(enabled);
372     }
373 
374     /**
375      * Set the primary continue button text to the given text.
376      */
setPrimaryToolbarButtonText(String text)377     public void setPrimaryToolbarButtonText(String text) {
378         mPrimaryToolbarButton.setText(text);
379     }
380 
381     /**
382      * Set the primary continue button onClickListener to the given listener. Can be null if the
383      * listener should be overridden so no callback is made. All changes to primary toolbar
384      * button's onClickListener should be made here so they can be stored through changes to the
385      * button.
386      */
setPrimaryToolbarButtonListener(@ullable View.OnClickListener listener)387     public void setPrimaryToolbarButtonListener(@Nullable View.OnClickListener listener) {
388         mPrimaryToolbarButtonOnClick = listener;
389         mPrimaryToolbarButton.setOnClickListener(listener);
390     }
391 
392     /**
393      * Getter for the flatness of the primary toolbar button.
394      */
getPrimaryToolbarButtonFlat()395     public boolean getPrimaryToolbarButtonFlat() {
396         return mPrimaryToolbarButtonFlat;
397     }
398 
399     /**
400      * Changes the button in the primary slot to a flat theme, maintaining the text, visibility,
401      * whether it is enabled, and id.
402      * <p>NOTE: that other attributes set manually on the primaryToolbarButton will be lost on calls
403      * to this method as the button will be replaced.</p>
404      */
setPrimaryToolbarButtonFlat(boolean isFlat)405     public void setPrimaryToolbarButtonFlat(boolean isFlat) {
406         // Do nothing if the state isn't changing.
407         if (isFlat == mPrimaryToolbarButtonFlat) {
408             return;
409         }
410         Button newPrimaryButton = createPrimaryToolbarButton(isFlat);
411 
412         ViewGroup parent = (ViewGroup) findViewById(R.id.button_container);
413         int buttonIndex = parent.indexOfChild(mPrimaryToolbarButton);
414         parent.removeViewAt(buttonIndex);
415         parent.addView(newPrimaryButton, buttonIndex);
416 
417         // Update state of layout
418         setPrimaryToolbarButton(newPrimaryButton);
419         mPrimaryToolbarButtonFlat = isFlat;
420     }
421 
422     @VisibleForTesting
createPrimaryToolbarButton(boolean isFlat)423     Button createPrimaryToolbarButton(boolean isFlat) {
424         int layoutId = isFlat ? R.layout.flat_button : R.layout.primary_button;
425         Button newPrimaryButton = (Button) inflate(getContext(), layoutId, null);
426         newPrimaryButton.setId(mPrimaryToolbarButton.getId());
427         newPrimaryButton.setVisibility(mPrimaryToolbarButton.getVisibility());
428         newPrimaryButton.setEnabled(mPrimaryToolbarButton.isEnabled());
429         newPrimaryButton.setText(mPrimaryToolbarButton.getText());
430         newPrimaryButton.setOnClickListener(mPrimaryToolbarButtonOnClick);
431         newPrimaryButton.setLayoutParams(mPrimaryToolbarButton.getLayoutParams());
432 
433         return newPrimaryButton;
434     }
435 
436     /**
437      * Gets the secondary toolbar button.
438      */
getSecondaryToolbarButton()439     public Button getSecondaryToolbarButton() {
440         return mSecondaryToolbarButton;
441     }
442 
443     /**
444      * Set the secondary continue button visibility to the given visibility.
445      */
setSecondaryToolbarButtonVisible(boolean visible)446     public void setSecondaryToolbarButtonVisible(boolean visible) {
447         // If not setting it visible and it hasn't been inflated yet then don't inflate.
448         if (!visible && mSecondaryToolbarButton == null) {
449             return;
450         }
451         maybeInflateSecondaryToolbarButton();
452         setViewVisible(mSecondaryToolbarButton, visible);
453     }
454 
455     /**
456      * Sets whether the secondary continue button is enabled.
457      */
setSecondaryToolbarButtonEnabled(boolean enabled)458     public void setSecondaryToolbarButtonEnabled(boolean enabled) {
459         maybeInflateSecondaryToolbarButton();
460         mSecondaryToolbarButton.setEnabled(enabled);
461     }
462 
463     /**
464      * Sets the secondary continue button text to the given text.
465      */
setSecondaryToolbarButtonText(String text)466     public void setSecondaryToolbarButtonText(String text) {
467         maybeInflateSecondaryToolbarButton();
468         mSecondaryToolbarButton.setText(text);
469     }
470 
471     /**
472      * Sets the secondary continue button onClickListener to the given listener. Can be null if the
473      * listener should be overridden so no callback is made.
474      */
setSecondaryToolbarButtonListener(@ullable View.OnClickListener listener)475     public void setSecondaryToolbarButtonListener(@Nullable View.OnClickListener listener) {
476         maybeInflateSecondaryToolbarButton();
477         mSecondaryToolbarButton.setOnClickListener(listener);
478     }
479 
480     /**
481      * Gets the progress bar.
482      */
getProgressBar()483     public ProgressBar getProgressBar() {
484         return mProgressBar;
485     }
486 
487     /**
488      * Sets the progress bar visibility to the given visibility.
489      */
setProgressBarVisible(boolean visible)490     public void setProgressBarVisible(boolean visible) {
491         setViewVisible(mProgressBar, visible);
492     }
493 
494     /**
495      * Sets the progress bar indeterminate/determinate state.
496      */
setProgressBarIndeterminate(boolean indeterminate)497     public void setProgressBarIndeterminate(boolean indeterminate) {
498         mProgressBar.setIndeterminate(indeterminate);
499     }
500 
501     /**
502      * Sets the progress bar's progress.
503      */
setProgressBarProgress(int progress)504     public void setProgressBarProgress(int progress) {
505         setProgressBarIndeterminate(false);
506         mProgressBar.setProgress(progress);
507     }
508 
509     /**
510      * Sets the locale to be used for rendering.
511      */
applyLocale(Locale locale)512     public void applyLocale(Locale locale) {
513         if (locale == null) {
514             return;
515         }
516         int direction = TextUtils.getLayoutDirectionFromLocale(locale);
517         setLayoutDirection(direction);
518 
519         mToolbarTitle.setTextLocale(locale);
520         mToolbarTitle.setLayoutDirection(direction);
521 
522         mPrimaryToolbarButton.setTextLocale(locale);
523         mPrimaryToolbarButton.setLayoutDirection(direction);
524 
525         mSecondaryToolbarButton.setTextLocale(locale);
526         mSecondaryToolbarButton.setLayoutDirection(direction);
527     }
528 
529     /**
530      * Sets the title bar view.
531      */
setTitleBar(View titleBar)532     private void setTitleBar(View titleBar) {
533         mTitleBar = titleBar;
534     }
535 
536     /**
537      * A method that inflates the SecondaryToolbarButton if it is has not already been
538      * inflated. If it has been inflated already this method will do nothing.
539      */
maybeInflateSecondaryToolbarButton()540     private void maybeInflateSecondaryToolbarButton() {
541         ViewStub secondaryToolbarButtonStub = findViewById(R.id.secondary_toolbar_button_stub);
542         // If the secondaryToolbarButtonStub is null then the stub has been inflated so there is
543         // nothing to do.
544         if (secondaryToolbarButtonStub != null) {
545             secondaryToolbarButtonStub.inflate();
546             mSecondaryToolbarButton = findViewById(R.id.secondary_toolbar_button);
547             setSecondaryToolbarButtonVisible(false);
548 
549             setBackground(
550                     mSecondaryToolbarButton,
551                     PartnerConfig.CONFIG_TOOLBAR_SECONDARY_BUTTON_BG,
552                     PartnerConfig.CONFIG_TOOLBAR_SECONDARY_BUTTON_BG_COLOR);
553 
554             setButtonPadding(mSecondaryToolbarButton);
555             setButtonTypeFace(mSecondaryToolbarButton);
556             setButtonTextSize(mSecondaryToolbarButton);
557             setButtonTextColor(
558                     mSecondaryToolbarButton,
559                     PartnerConfig.CONFIG_TOOLBAR_SECONDARY_BUTTON_TEXT_COLOR);
560 
561             // Set button spacing
562             float marginEnd = PartnerConfigHelper.get(getContext()).getDimension(
563                     getContext(),
564                     PartnerConfig.CONFIG_TOOLBAR_BUTTON_SPACING);
565 
566             MarginLayoutParams layoutParams =
567                     (MarginLayoutParams) mSecondaryToolbarButton.getLayoutParams();
568             layoutParams.setMarginEnd(Math.round(marginEnd));
569         }
570     }
571 
572     /** Sets button text color using partner overlay if exists */
573     @VisibleForTesting
setButtonTextColor(TextView button, PartnerConfig config)574     void setButtonTextColor(TextView button, PartnerConfig config) {
575         int color = mPartnerConfigHelper.getColor(getContext(), config);
576         if (color != 0) {
577             button.setTextColor(color);
578         }
579     }
580 
581     /**
582      * Sets background using partner overlay if exists. Background color and radius are only
583      * applied if background resource doesn't exist. Otherwise default background color and radius
584      * may override what's set in the background.
585      */
586     @VisibleForTesting
setBackground(View view, PartnerConfig bgConfig, PartnerConfig bgColorConfig)587     void setBackground(View view, PartnerConfig bgConfig, PartnerConfig bgColorConfig) {
588         Drawable background = mPartnerConfigHelper.getDrawable(getContext(), bgConfig);
589         if (background == null) {
590             if (view instanceof Button) {
591                 setButtonRadius((Button) view);
592             }
593             setBackgroundColor(view, bgColorConfig);
594         } else {
595             view.setBackground(background);
596         }
597     }
598 
599     /** Sets button background color using partner overlay if exists */
600     @VisibleForTesting
setBackgroundColor(View button, PartnerConfig config)601     void setBackgroundColor(View button, PartnerConfig config) {
602         int color = mPartnerConfigHelper.getColor(getContext(), config);
603         if (color != 0) {
604             Drawable background = button.getBackground();
605             if (background != null) {
606                 background.mutate().setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
607             }
608         }
609     }
610 
611     /** Sets button text size using partner overlay if exists */
612     @VisibleForTesting
setButtonTextSize(TextView button)613     void setButtonTextSize(TextView button) {
614         float dimension = mPartnerConfigHelper.getDimension(
615                 getContext(),
616                 PartnerConfig.CONFIG_TOOLBAR_BUTTON_TEXT_SIZE);
617         if (dimension != 0) {
618             button.setTextSize(TypedValue.COMPLEX_UNIT_PX, dimension);
619         }
620     }
621 
622     /** Sets button type face with partner overlay if exists */
setButtonTypeFace(TextView button)623     private void setButtonTypeFace(TextView button) {
624         String fontFamily = mPartnerConfigHelper.getString(
625                 getContext(),
626                 PartnerConfig.CONFIG_TOOLBAR_BUTTON_FONT_FAMILY);
627         if (TextUtils.isEmpty(fontFamily)) {
628             return;
629         }
630 
631         Typeface typeface = Typeface.create(fontFamily, Typeface.NORMAL);
632         if (Objects.equals(typeface, Typeface.DEFAULT)) {
633             Log.w(TAG, String.format(
634                     "Couldn't find font: %s. Setting default font.",
635                     fontFamily));
636         }
637         button.setTypeface(typeface);
638     }
639 
640     /** Sets button radius using partner overlay if exists */
setButtonRadius(Button button)641     private void setButtonRadius(Button button) {
642         float radius = mPartnerConfigHelper.getDimension(
643                 getContext(),
644                 PartnerConfig.CONFIG_TOOLBAR_BUTTON_RADIUS);
645 
646         GradientDrawable gradientDrawable = getGradientDrawable(button);
647         if (gradientDrawable != null) {
648             gradientDrawable.setCornerRadius(radius);
649         }
650     }
651 
setButtonPadding(Button button)652     private void setButtonPadding(Button button) {
653         int hPadding = Math.round(
654                 PartnerConfigHelper.get(getContext()).getDimension(
655                         getContext(),
656                         PartnerConfig.CONFIG_TOOLBAR_BUTTON_PADDING_HORIZONTAL)
657         );
658         int vPadding = Math.round(
659                 PartnerConfigHelper.get(getContext()).getDimension(
660                         getContext(),
661                         PartnerConfig.CONFIG_TOOLBAR_BUTTON_PADDING_VERTICAL)
662         );
663         button.setPadding(hPadding, vPadding, hPadding, vPadding);
664     }
665 
getGradientDrawable(Button button)666     private GradientDrawable getGradientDrawable(Button button) {
667         Drawable drawable = button.getBackground();
668         if (drawable instanceof InsetDrawable) {
669             return getGradientDrawableFromInsetDrawable((InsetDrawable) drawable);
670         }
671 
672         if (drawable instanceof RippleDrawable) {
673             drawable = ((RippleDrawable) drawable).getDrawable(0);
674             if (drawable instanceof InsetDrawable) {
675                 return getGradientDrawableFromInsetDrawable((InsetDrawable) drawable);
676             }
677             return (GradientDrawable) drawable;
678         }
679 
680         return null;
681     }
682 
getGradientDrawableFromInsetDrawable(InsetDrawable insetDrawable)683     private GradientDrawable getGradientDrawableFromInsetDrawable(InsetDrawable insetDrawable) {
684         return (GradientDrawable) insetDrawable.getDrawable();
685     }
686 }
687