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 17 package com.google.android.setupdesign.template; 18 19 import android.content.res.ColorStateList; 20 import android.os.Build; 21 import android.os.Build.VERSION_CODES; 22 import androidx.annotation.Nullable; 23 import android.view.View; 24 import android.view.ViewStub; 25 import android.widget.ProgressBar; 26 import com.google.android.setupcompat.internal.TemplateLayout; 27 import com.google.android.setupcompat.template.Mixin; 28 import com.google.android.setupdesign.R; 29 30 /** A {@link Mixin} for showing a progress bar. */ 31 public class ProgressBarMixin implements Mixin { 32 33 private final TemplateLayout templateLayout; 34 35 @Nullable private ColorStateList color; 36 37 /** @param layout The layout this mixin belongs to. */ ProgressBarMixin(TemplateLayout layout)38 public ProgressBarMixin(TemplateLayout layout) { 39 templateLayout = layout; 40 } 41 42 /** @return True if the progress bar is currently shown. */ isShown()43 public boolean isShown() { 44 final View progressBar = templateLayout.findManagedViewById(R.id.sud_layout_progress); 45 return progressBar != null && progressBar.getVisibility() == View.VISIBLE; 46 } 47 48 /** 49 * Sets whether the progress bar is shown. If the progress bar has not been inflated from the 50 * stub, this method will inflate the progress bar. 51 * 52 * @param shown True to show the progress bar, false to hide it. 53 */ setShown(boolean shown)54 public void setShown(boolean shown) { 55 if (shown) { 56 View progressBar = getProgressBar(); 57 if (progressBar != null) { 58 progressBar.setVisibility(View.VISIBLE); 59 } 60 } else { 61 View progressBar = peekProgressBar(); 62 if (progressBar != null) { 63 progressBar.setVisibility(View.GONE); 64 } 65 } 66 } 67 68 /** 69 * Gets the progress bar in the layout. If the progress bar has not been used before, it will be 70 * installed (i.e. inflated from its view stub). 71 * 72 * @return The progress bar of this layout. May be null only if the template used doesn't have a 73 * progress bar built-in. 74 */ getProgressBar()75 private ProgressBar getProgressBar() { 76 final View progressBar = peekProgressBar(); 77 if (progressBar == null) { 78 final ViewStub progressBarStub = 79 (ViewStub) templateLayout.findManagedViewById(R.id.sud_layout_progress_stub); 80 if (progressBarStub != null) { 81 progressBarStub.inflate(); 82 } 83 setColor(color); 84 } 85 return peekProgressBar(); 86 } 87 88 /** 89 * Gets the progress bar in the layout only if it has been installed. {@link #setShown(boolean)} 90 * should be called before this to ensure the progress bar is set up correctly. 91 * 92 * @return The progress bar of this layout, or null if the progress bar is not installed. The null 93 * case can happen either if {@link #setShown(boolean)} with true was not called before this, 94 * or if the template does not contain a progress bar. 95 */ peekProgressBar()96 public ProgressBar peekProgressBar() { 97 return (ProgressBar) templateLayout.findManagedViewById(R.id.sud_layout_progress); 98 } 99 100 /** Sets the color of the indeterminate progress bar. This method is a no-op on SDK < 21. */ setColor(@ullable ColorStateList color)101 public void setColor(@Nullable ColorStateList color) { 102 this.color = color; 103 if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { 104 final ProgressBar bar = peekProgressBar(); 105 if (bar != null) { 106 bar.setIndeterminateTintList(color); 107 if (Build.VERSION.SDK_INT >= VERSION_CODES.M || color != null) { 108 // There is a bug in Lollipop where setting the progress tint color to null 109 // will crash with "java.lang.NullPointerException: Attempt to invoke virtual 110 // method 'int android.graphics.Paint.getAlpha()' on a null object reference" 111 // at android.graphics.drawable.NinePatchDrawable.draw(:250) 112 // The bug doesn't affect ProgressBar on M because it uses ShapeDrawable instead 113 // of NinePatchDrawable. (commit 6a8253fdc9f4574c28b4beeeed90580ffc93734a) 114 bar.setProgressBackgroundTintList(color); 115 } 116 } 117 } 118 } 119 120 /** 121 * @return The color previously set in {@link #setColor(ColorStateList)}, or null if the color is 122 * not set. In case of null, the color of the progress bar will be inherited from the theme. 123 */ 124 @Nullable getColor()125 public ColorStateList getColor() { 126 return color; 127 } 128 } 129